aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@csr.com>2009-01-22 19:12:32 +0000
committerDavid Vrabel <david.vrabel@csr.com>2009-01-22 19:12:32 +0000
commitdff243f7cb3a2ebbb09093066c1bc4a90ff5b3a4 (patch)
tree1c63e7c2f879cd322ca785671b74b4ff796dd24c /drivers
parentwusb: timeout when waiting for ASL/PZL updates in whci-hcd (diff)
parentMerge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband (diff)
downloadlinux-dev-dff243f7cb3a2ebbb09093066c1bc4a90ff5b3a4.tar.xz
linux-dev-dff243f7cb3a2ebbb09093066c1bc4a90ff5b3a4.zip
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into for-upstream
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile6
-rw-r--r--drivers/acpi/Kconfig84
-rw-r--r--drivers/acpi/Makefile25
-rw-r--r--drivers/acpi/acpi_memhotplug.c2
-rw-r--r--drivers/acpi/acpica/Makefile44
-rw-r--r--drivers/acpi/acpica/accommon.h63
-rw-r--r--drivers/acpi/acpica/acconfig.h217
-rw-r--r--drivers/acpi/acpica/acdebug.h231
-rw-r--r--drivers/acpi/acpica/acdispat.h345
-rw-r--r--drivers/acpi/acpica/acevents.h218
-rw-r--r--drivers/acpi/acpica/acglobal.h394
-rw-r--r--drivers/acpi/acpica/achware.h119
-rw-r--r--drivers/acpi/acpica/acinterp.h529
-rw-r--r--drivers/acpi/acpica/aclocal.h990
-rw-r--r--drivers/acpi/acpica/acmacros.h577
-rw-r--r--drivers/acpi/acpica/acnamesp.h324
-rw-r--r--drivers/acpi/acpica/acobject.h446
-rw-r--r--drivers/acpi/acpica/acopcode.h323
-rw-r--r--drivers/acpi/acpica/acparser.h234
-rw-r--r--drivers/acpi/acpica/acpredef.h371
-rw-r--r--drivers/acpi/acpica/acresrc.h336
-rw-r--r--drivers/acpi/acpica/acstruct.h228
-rw-r--r--drivers/acpi/acpica/actables.h117
-rw-r--r--drivers/acpi/acpica/acutils.h549
-rw-r--r--drivers/acpi/acpica/amlcode.h494
-rw-r--r--drivers/acpi/acpica/amlresrc.h311
-rw-r--r--drivers/acpi/acpica/dsfield.c (renamed from drivers/acpi/dispatcher/dsfield.c)11
-rw-r--r--drivers/acpi/acpica/dsinit.c (renamed from drivers/acpi/dispatcher/dsinit.c)7
-rw-r--r--drivers/acpi/acpica/dsmethod.c (renamed from drivers/acpi/dispatcher/dsmethod.c)14
-rw-r--r--drivers/acpi/acpica/dsmthdat.c (renamed from drivers/acpi/dispatcher/dsmthdat.c)7
-rw-r--r--drivers/acpi/acpica/dsobject.c (renamed from drivers/acpi/dispatcher/dsobject.c)11
-rw-r--r--drivers/acpi/acpica/dsopcode.c (renamed from drivers/acpi/dispatcher/dsopcode.c)66
-rw-r--r--drivers/acpi/acpica/dsutils.c (renamed from drivers/acpi/dispatcher/dsutils.c)13
-rw-r--r--drivers/acpi/acpica/dswexec.c (renamed from drivers/acpi/dispatcher/dswexec.c)13
-rw-r--r--drivers/acpi/acpica/dswload.c (renamed from drivers/acpi/dispatcher/dswload.c)13
-rw-r--r--drivers/acpi/acpica/dswscope.c (renamed from drivers/acpi/dispatcher/dswscope.c)3
-rw-r--r--drivers/acpi/acpica/dswstate.c (renamed from drivers/acpi/dispatcher/dswstate.c)7
-rw-r--r--drivers/acpi/acpica/evevent.c (renamed from drivers/acpi/events/evevent.c)17
-rw-r--r--drivers/acpi/acpica/evgpe.c (renamed from drivers/acpi/events/evgpe.c)53
-rw-r--r--drivers/acpi/acpica/evgpeblk.c (renamed from drivers/acpi/events/evgpeblk.c)82
-rw-r--r--drivers/acpi/acpica/evmisc.c (renamed from drivers/acpi/events/evmisc.c)62
-rw-r--r--drivers/acpi/acpica/evregion.c (renamed from drivers/acpi/events/evregion.c)140
-rw-r--r--drivers/acpi/acpica/evrgnini.c (renamed from drivers/acpi/events/evrgnini.c)46
-rw-r--r--drivers/acpi/acpica/evsci.c (renamed from drivers/acpi/events/evsci.c)13
-rw-r--r--drivers/acpi/acpica/evxface.c (renamed from drivers/acpi/events/evxface.c)9
-rw-r--r--drivers/acpi/acpica/evxfevnt.c (renamed from drivers/acpi/events/evxfevnt.c)170
-rw-r--r--drivers/acpi/acpica/evxfregn.c (renamed from drivers/acpi/events/evxfregn.c)5
-rw-r--r--drivers/acpi/acpica/exconfig.c (renamed from drivers/acpi/executer/exconfig.c)9
-rw-r--r--drivers/acpi/acpica/exconvrt.c (renamed from drivers/acpi/executer/exconvrt.c)5
-rw-r--r--drivers/acpi/acpica/excreate.c (renamed from drivers/acpi/executer/excreate.c)7
-rw-r--r--drivers/acpi/acpica/exdump.c (renamed from drivers/acpi/executer/exdump.c)7
-rw-r--r--drivers/acpi/acpica/exfield.c (renamed from drivers/acpi/executer/exfield.c)5
-rw-r--r--drivers/acpi/acpica/exfldio.c (renamed from drivers/acpi/executer/exfldio.c)20
-rw-r--r--drivers/acpi/acpica/exmisc.c (renamed from drivers/acpi/executer/exmisc.c)7
-rw-r--r--drivers/acpi/acpica/exmutex.c (renamed from drivers/acpi/executer/exmutex.c)5
-rw-r--r--drivers/acpi/acpica/exnames.c (renamed from drivers/acpi/executer/exnames.c)5
-rw-r--r--drivers/acpi/acpica/exoparg1.c (renamed from drivers/acpi/executer/exoparg1.c)11
-rw-r--r--drivers/acpi/acpica/exoparg2.c (renamed from drivers/acpi/executer/exoparg2.c)9
-rw-r--r--drivers/acpi/acpica/exoparg3.c (renamed from drivers/acpi/executer/exoparg3.c)7
-rw-r--r--drivers/acpi/acpica/exoparg6.c (renamed from drivers/acpi/executer/exoparg6.c)7
-rw-r--r--drivers/acpi/acpica/exprep.c (renamed from drivers/acpi/executer/exprep.c)9
-rw-r--r--drivers/acpi/acpica/exregion.c (renamed from drivers/acpi/executer/exregion.c)3
-rw-r--r--drivers/acpi/acpica/exresnte.c (renamed from drivers/acpi/executer/exresnte.c)7
-rw-r--r--drivers/acpi/acpica/exresolv.c (renamed from drivers/acpi/executer/exresolv.c)11
-rw-r--r--drivers/acpi/acpica/exresop.c (renamed from drivers/acpi/executer/exresop.c)9
-rw-r--r--drivers/acpi/acpica/exstore.c (renamed from drivers/acpi/executer/exstore.c)11
-rw-r--r--drivers/acpi/acpica/exstoren.c (renamed from drivers/acpi/executer/exstoren.c)5
-rw-r--r--drivers/acpi/acpica/exstorob.c (renamed from drivers/acpi/executer/exstorob.c)3
-rw-r--r--drivers/acpi/acpica/exsystem.c (renamed from drivers/acpi/executer/exsystem.c)3
-rw-r--r--drivers/acpi/acpica/exutils.c (renamed from drivers/acpi/executer/exutils.c)5
-rw-r--r--drivers/acpi/acpica/hwacpi.c (renamed from drivers/acpi/hardware/hwacpi.c)1
-rw-r--r--drivers/acpi/acpica/hwgpe.c (renamed from drivers/acpi/hardware/hwgpe.c)78
-rw-r--r--drivers/acpi/acpica/hwregs.c353
-rw-r--r--drivers/acpi/acpica/hwsleep.c (renamed from drivers/acpi/hardware/hwsleep.c)76
-rw-r--r--drivers/acpi/acpica/hwtimer.c (renamed from drivers/acpi/hardware/hwtimer.c)1
-rw-r--r--drivers/acpi/acpica/hwxface.c (renamed from drivers/acpi/hardware/hwregs.c)744
-rw-r--r--drivers/acpi/acpica/nsaccess.c (renamed from drivers/acpi/namespace/nsaccess.c)18
-rw-r--r--drivers/acpi/acpica/nsalloc.c (renamed from drivers/acpi/namespace/nsalloc.c)3
-rw-r--r--drivers/acpi/acpica/nsdump.c (renamed from drivers/acpi/namespace/nsdump.c)3
-rw-r--r--drivers/acpi/acpica/nsdumpdv.c (renamed from drivers/acpi/namespace/nsdumpdv.c)3
-rw-r--r--drivers/acpi/acpica/nseval.c (renamed from drivers/acpi/namespace/nseval.c)77
-rw-r--r--drivers/acpi/acpica/nsinit.c (renamed from drivers/acpi/namespace/nsinit.c)7
-rw-r--r--drivers/acpi/acpica/nsload.c (renamed from drivers/acpi/namespace/nsload.c)7
-rw-r--r--drivers/acpi/acpica/nsnames.c (renamed from drivers/acpi/namespace/nsnames.c)5
-rw-r--r--drivers/acpi/acpica/nsobject.c (renamed from drivers/acpi/namespace/nsobject.c)3
-rw-r--r--drivers/acpi/acpica/nsparse.c (renamed from drivers/acpi/namespace/nsparse.c)9
-rw-r--r--drivers/acpi/acpica/nspredef.c (renamed from drivers/acpi/namespace/nspredef.c)261
-rw-r--r--drivers/acpi/acpica/nssearch.c (renamed from drivers/acpi/namespace/nssearch.c)3
-rw-r--r--drivers/acpi/acpica/nsutils.c (renamed from drivers/acpi/namespace/nsutils.c)15
-rw-r--r--drivers/acpi/acpica/nswalk.c (renamed from drivers/acpi/namespace/nswalk.c)3
-rw-r--r--drivers/acpi/acpica/nsxfeval.c (renamed from drivers/acpi/namespace/nsxfeval.c)5
-rw-r--r--drivers/acpi/acpica/nsxfname.c (renamed from drivers/acpi/namespace/nsxfname.c)3
-rw-r--r--drivers/acpi/acpica/nsxfobj.c (renamed from drivers/acpi/namespace/nsxfobj.c)3
-rw-r--r--drivers/acpi/acpica/psargs.c (renamed from drivers/acpi/parser/psargs.c)9
-rw-r--r--drivers/acpi/acpica/psloop.c (renamed from drivers/acpi/parser/psloop.c)7
-rw-r--r--drivers/acpi/acpica/psopcode.c (renamed from drivers/acpi/parser/psopcode.c)7
-rw-r--r--drivers/acpi/acpica/psparse.c (renamed from drivers/acpi/parser/psparse.c)23
-rw-r--r--drivers/acpi/acpica/psscope.c (renamed from drivers/acpi/parser/psscope.c)3
-rw-r--r--drivers/acpi/acpica/pstree.c (renamed from drivers/acpi/parser/pstree.c)5
-rw-r--r--drivers/acpi/acpica/psutils.c (renamed from drivers/acpi/parser/psutils.c)5
-rw-r--r--drivers/acpi/acpica/pswalk.c (renamed from drivers/acpi/parser/pswalk.c)3
-rw-r--r--drivers/acpi/acpica/psxface.c (renamed from drivers/acpi/parser/psxface.c)40
-rw-r--r--drivers/acpi/acpica/rsaddr.c (renamed from drivers/acpi/resources/rsaddr.c)3
-rw-r--r--drivers/acpi/acpica/rscalc.c (renamed from drivers/acpi/resources/rscalc.c)5
-rw-r--r--drivers/acpi/acpica/rscreate.c (renamed from drivers/acpi/resources/rscreate.c)7
-rw-r--r--drivers/acpi/acpica/rsdump.c (renamed from drivers/acpi/resources/rsdump.c)3
-rw-r--r--drivers/acpi/acpica/rsinfo.c (renamed from drivers/acpi/resources/rsinfo.c)3
-rw-r--r--drivers/acpi/acpica/rsio.c (renamed from drivers/acpi/resources/rsio.c)3
-rw-r--r--drivers/acpi/acpica/rsirq.c (renamed from drivers/acpi/resources/rsirq.c)3
-rw-r--r--drivers/acpi/acpica/rslist.c (renamed from drivers/acpi/resources/rslist.c)3
-rw-r--r--drivers/acpi/acpica/rsmemory.c (renamed from drivers/acpi/resources/rsmemory.c)3
-rw-r--r--drivers/acpi/acpica/rsmisc.c (renamed from drivers/acpi/resources/rsmisc.c)3
-rw-r--r--drivers/acpi/acpica/rsutils.c (renamed from drivers/acpi/resources/rsutils.c)5
-rw-r--r--drivers/acpi/acpica/rsxface.c (renamed from drivers/acpi/resources/rsxface.c)5
-rw-r--r--drivers/acpi/acpica/tbfadt.c (renamed from drivers/acpi/tables/tbfadt.c)252
-rw-r--r--drivers/acpi/acpica/tbfind.c (renamed from drivers/acpi/tables/tbfind.c)3
-rw-r--r--drivers/acpi/acpica/tbinstal.c (renamed from drivers/acpi/tables/tbinstal.c)5
-rw-r--r--drivers/acpi/acpica/tbutils.c (renamed from drivers/acpi/tables/tbutils.c)30
-rw-r--r--drivers/acpi/acpica/tbxface.c (renamed from drivers/acpi/tables/tbxface.c)5
-rw-r--r--drivers/acpi/acpica/tbxfroot.c (renamed from drivers/acpi/tables/tbxfroot.c)3
-rw-r--r--drivers/acpi/acpica/utalloc.c (renamed from drivers/acpi/utilities/utalloc.c)3
-rw-r--r--drivers/acpi/acpica/utcopy.c (renamed from drivers/acpi/utilities/utcopy.c)3
-rw-r--r--drivers/acpi/acpica/utdebug.c (renamed from drivers/acpi/utilities/utdebug.c)95
-rw-r--r--drivers/acpi/acpica/utdelete.c (renamed from drivers/acpi/utilities/utdelete.c)7
-rw-r--r--drivers/acpi/acpica/uteval.c (renamed from drivers/acpi/utilities/uteval.c)11
-rw-r--r--drivers/acpi/acpica/utglobal.c (renamed from drivers/acpi/utilities/utglobal.c)12
-rw-r--r--drivers/acpi/acpica/utinit.c (renamed from drivers/acpi/utilities/utinit.c)7
-rw-r--r--drivers/acpi/acpica/utmath.c (renamed from drivers/acpi/utilities/utmath.c)1
-rw-r--r--drivers/acpi/acpica/utmisc.c (renamed from drivers/acpi/utilities/utmisc.c)23
-rw-r--r--drivers/acpi/acpica/utmutex.c (renamed from drivers/acpi/utilities/utmutex.c)1
-rw-r--r--drivers/acpi/acpica/utobject.c (renamed from drivers/acpi/utilities/utobject.c)7
-rw-r--r--drivers/acpi/acpica/utresrc.c (renamed from drivers/acpi/utilities/utresrc.c)3
-rw-r--r--drivers/acpi/acpica/utstate.c (renamed from drivers/acpi/utilities/utstate.c)1
-rw-r--r--drivers/acpi/acpica/utxface.c (renamed from drivers/acpi/utilities/utxface.c)18
-rw-r--r--drivers/acpi/battery.c5
-rw-r--r--drivers/acpi/cm_sbs.c3
-rw-r--r--drivers/acpi/debug.c1
-rw-r--r--drivers/acpi/dispatcher/Makefile9
-rw-r--r--drivers/acpi/ec.c106
-rw-r--r--drivers/acpi/events/Makefile9
-rw-r--r--drivers/acpi/executer/Makefile10
-rw-r--r--drivers/acpi/hardware/Makefile9
-rw-r--r--drivers/acpi/namespace/Makefile12
-rw-r--r--drivers/acpi/numa.c1
-rw-r--r--drivers/acpi/osl.c4
-rw-r--r--drivers/acpi/parser/Makefile8
-rw-r--r--drivers/acpi/pci_bind.c90
-rw-r--r--drivers/acpi/pci_irq.c472
-rw-r--r--drivers/acpi/pci_link.c6
-rw-r--r--drivers/acpi/pci_root.c20
-rw-r--r--drivers/acpi/power.c6
-rw-r--r--drivers/acpi/proc.c (renamed from drivers/acpi/sleep/proc.c)65
-rw-r--r--drivers/acpi/reboot.c2
-rw-r--r--drivers/acpi/resources/Makefile10
-rw-r--r--drivers/acpi/sbshc.c1
-rw-r--r--drivers/acpi/scan.c1
-rw-r--r--drivers/acpi/sleep.c (renamed from drivers/acpi/sleep/main.c)79
-rw-r--r--drivers/acpi/sleep.h (renamed from drivers/acpi/sleep/sleep.h)0
-rw-r--r--drivers/acpi/sleep/Makefile5
-rw-r--r--drivers/acpi/system.c63
-rw-r--r--drivers/acpi/tables/Makefile7
-rw-r--r--drivers/acpi/thermal.c16
-rw-r--r--drivers/acpi/utilities/Makefile9
-rw-r--r--drivers/acpi/utilities/utcache.c314
-rw-r--r--drivers/acpi/video.c20
-rw-r--r--drivers/acpi/video_detect.c4
-rw-r--r--drivers/acpi/wakeup.c (renamed from drivers/acpi/sleep/wakeup.c)6
-rw-r--r--drivers/amba/bus.c3
-rw-r--r--drivers/ata/Kconfig9
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.c13
-rw-r--r--drivers/ata/ata_piix.c51
-rw-r--r--drivers/ata/libata-acpi.c6
-rw-r--r--drivers/ata/libata-core.c201
-rw-r--r--drivers/ata/libata-scsi.c17
-rw-r--r--drivers/ata/libata-sff.c216
-rw-r--r--drivers/ata/pata_acpi.c6
-rw-r--r--drivers/ata/pata_ali.c111
-rw-r--r--drivers/ata/pata_amd.c4
-rw-r--r--drivers/ata/pata_atiixp.c32
-rw-r--r--drivers/ata/pata_hpt366.c109
-rw-r--r--drivers/ata/pata_hpt3x3.c49
-rw-r--r--drivers/ata/pata_it821x.c17
-rw-r--r--drivers/ata/pata_mpiix.c3
-rw-r--r--drivers/ata/pata_octeon_cf.c965
-rw-r--r--drivers/ata/pata_platform.c2
-rw-r--r--drivers/ata/pata_sil680.c4
-rw-r--r--drivers/ata/sata_fsl.c2
-rw-r--r--drivers/ata/sata_sil24.c7
-rw-r--r--drivers/ata/sata_via.c2
-rw-r--r--drivers/atm/iphase.c6
-rw-r--r--drivers/base/Kconfig2
-rw-r--r--drivers/base/base.h26
-rw-r--r--drivers/base/bus.c40
-rw-r--r--drivers/base/core.c45
-rw-r--r--drivers/base/dd.c13
-rw-r--r--drivers/base/driver.c13
-rw-r--r--drivers/base/topology.c1
-rw-r--r--drivers/block/amiflop.c40
-rw-r--r--drivers/block/nbd.c4
-rw-r--r--drivers/block/ps3disk.c18
-rw-r--r--drivers/block/sunvdc.c8
-rw-r--r--drivers/block/ub.c11
-rw-r--r--drivers/block/xsysace.c1
-rw-r--r--drivers/char/Kconfig1
-rw-r--r--drivers/char/amiserial.c36
-rw-r--r--drivers/char/bsr.c2
-rw-r--r--drivers/char/epca.c2
-rw-r--r--drivers/char/hvc_beat.c4
-rw-r--r--drivers/char/hvc_console.c12
-rw-r--r--drivers/char/hvc_irq.c2
-rw-r--r--drivers/char/hvc_iucv.c420
-rw-r--r--drivers/char/hw_random/n2-drv.c2
-rw-r--r--drivers/char/ps3flash.c18
-rw-r--r--drivers/char/pty.c6
-rw-r--r--drivers/char/rtc.c17
-rw-r--r--drivers/char/ser_a2232.c12
-rw-r--r--drivers/char/synclink_gt.c16
-rw-r--r--drivers/char/sysrq.c6
-rw-r--r--drivers/char/tpm/tpm_bios.c2
-rw-r--r--drivers/char/tpm/tpm_nsc.c35
-rw-r--r--drivers/char/tty_ioctl.c2
-rw-r--r--drivers/char/vme_scc.c166
-rw-r--r--drivers/char/vt.c3
-rw-r--r--drivers/cpufreq/Kconfig4
-rw-r--r--drivers/cpufreq/cpufreq.c42
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c2
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c4
-rw-r--r--drivers/cpuidle/governors/menu.c10
-rw-r--r--drivers/dca/dca-core.c2
-rw-r--r--drivers/dio/dio-sysfs.c19
-rw-r--r--drivers/dio/dio.c18
-rw-r--r--drivers/dma/Kconfig2
-rw-r--r--drivers/dma/dmaengine.c778
-rw-r--r--drivers/dma/dmatest.c129
-rw-r--r--drivers/dma/dw_dmac.c119
-rw-r--r--drivers/dma/fsldma.c5
-rw-r--r--drivers/dma/ioat.c92
-rw-r--r--drivers/dma/ioat_dma.c18
-rw-r--r--drivers/dma/iop-adma.c30
-rw-r--r--drivers/dma/mv_xor.c11
-rw-r--r--drivers/firewire/fw-card.c33
-rw-r--r--drivers/firewire/fw-device.c31
-rw-r--r--drivers/firewire/fw-device.h2
-rw-r--r--drivers/firewire/fw-sbp2.c21
-rw-r--r--drivers/firewire/fw-topology.c16
-rw-r--r--drivers/firewire/fw-transaction.c2
-rw-r--r--drivers/firewire/fw-transaction.h13
-rw-r--r--drivers/firmware/dcdbas.c9
-rw-r--r--drivers/firmware/dcdbas.h2
-rw-r--r--drivers/firmware/dell_rbu.c4
-rw-r--r--drivers/firmware/memmap.c6
-rw-r--r--drivers/gpio/max7301.c6
-rw-r--r--drivers/gpio/max732x.c6
-rw-r--r--drivers/gpio/mcp23s08.c6
-rw-r--r--drivers/gpio/pca953x.c6
-rw-r--r--drivers/gpio/pcf857x.c12
-rw-r--r--drivers/gpu/drm/drm_crtc.c2
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c175
-rw-r--r--drivers/gpu/drm/drm_irq.c18
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c10
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h23
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c193
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c6
-rw-r--r--drivers/gpu/drm/i915/intel_display.c43
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c7
-rw-r--r--drivers/hid/usbhid/hid-core.c9
-rw-r--r--drivers/hid/usbhid/hiddev.c2
-rw-r--r--drivers/hwmon/Kconfig71
-rw-r--r--drivers/hwmon/Makefile5
-rw-r--r--drivers/hwmon/abituguru3.c24
-rw-r--r--drivers/hwmon/adt7475.c1221
-rw-r--r--drivers/hwmon/applesmc.c5
-rw-r--r--drivers/hwmon/asb100.c5
-rw-r--r--drivers/hwmon/dme1737.c5
-rw-r--r--drivers/hwmon/f71805f.c5
-rw-r--r--drivers/hwmon/f71882fg.c1549
-rw-r--r--drivers/hwmon/fschmd.c450
-rw-r--r--drivers/hwmon/hp_accel.c334
-rw-r--r--drivers/hwmon/i5k_amb.c7
-rw-r--r--drivers/hwmon/it87.c37
-rw-r--r--drivers/hwmon/k8temp.c55
-rw-r--r--drivers/hwmon/lis3lv02d.c273
-rw-r--r--drivers/hwmon/lis3lv02d.h35
-rw-r--r--drivers/hwmon/lm70.c91
-rw-r--r--drivers/hwmon/ltc4245.c567
-rw-r--r--drivers/hwmon/pc87360.c6
-rw-r--r--drivers/hwmon/pc87427.c5
-rw-r--r--drivers/hwmon/sis5595.c5
-rw-r--r--drivers/hwmon/smsc47b397.c5
-rw-r--r--drivers/hwmon/smsc47m1.c5
-rw-r--r--drivers/hwmon/via686a.c5
-rw-r--r--drivers/hwmon/vt1211.c5
-rw-r--r--drivers/hwmon/vt8231.c5
-rw-r--r--drivers/hwmon/w83627ehf.c8
-rw-r--r--drivers/hwmon/w83627hf.c5
-rw-r--r--drivers/hwmon/w83781d.c5
-rw-r--r--drivers/hwmon/w83791d.c5
-rw-r--r--drivers/hwmon/w83792d.c5
-rw-r--r--drivers/hwmon/w83793.c5
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c4
-rw-r--r--drivers/i2c/busses/i2c-amd756-s4882.c4
-rw-r--r--drivers/i2c/busses/i2c-amd756.c5
-rw-r--r--drivers/i2c/busses/i2c-at91.c2
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c2
-rw-r--r--drivers/i2c/busses/i2c-i801.c50
-rw-r--r--drivers/i2c/busses/i2c-pxa.c4
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c2
-rw-r--r--drivers/i2c/busses/i2c-sh7760.c2
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c2
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c4
-rw-r--r--drivers/i2c/busses/i2c-sis630.c4
-rw-r--r--drivers/i2c/chips/Kconfig23
-rw-r--r--drivers/i2c/chips/Makefile2
-rw-r--r--drivers/i2c/chips/mcu_mpc8349emitx.c209
-rw-r--r--drivers/i2c/i2c-core.c8
-rw-r--r--drivers/ide/Kconfig5
-rw-r--r--drivers/ide/ide-acpi.c6
-rw-r--r--drivers/ide/ide-disk.c2
-rw-r--r--drivers/ide/ide-iops.c2
-rw-r--r--drivers/ide/ide-pm.c12
-rw-r--r--drivers/ide/ide-probe.c2
-rw-r--r--drivers/ide/it821x.c15
-rw-r--r--drivers/ide/sl82c105.c4
-rw-r--r--drivers/ide/tx4938ide.c1
-rw-r--r--drivers/ide/via82cxxx.c2
-rw-r--r--drivers/ieee1394/csr.c12
-rw-r--r--drivers/ieee1394/csr.h10
-rw-r--r--drivers/ieee1394/csr1212.c45
-rw-r--r--drivers/ieee1394/csr1212.h9
-rw-r--r--drivers/ieee1394/dv1394-private.h44
-rw-r--r--drivers/ieee1394/dv1394.c12
-rw-r--r--drivers/ieee1394/eth1394.c82
-rw-r--r--drivers/ieee1394/eth1394.h17
-rw-r--r--drivers/ieee1394/highlevel.c9
-rw-r--r--drivers/ieee1394/highlevel.h7
-rw-r--r--drivers/ieee1394/hosts.c6
-rw-r--r--drivers/ieee1394/hosts.h2
-rw-r--r--drivers/ieee1394/ieee1394.h3
-rw-r--r--drivers/ieee1394/nodemgr.c20
-rw-r--r--drivers/ieee1394/nodemgr.h3
-rw-r--r--drivers/ieee1394/ohci1394.c26
-rw-r--r--drivers/ieee1394/pcilynx.c2
-rw-r--r--drivers/ieee1394/pcilynx.h2
-rw-r--r--drivers/ieee1394/raw1394.c2
-rw-r--r--drivers/ieee1394/sbp2.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c16
-rw-r--r--drivers/infiniband/hw/ehca/ehca_hca.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c18
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c8
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mcast.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.c144
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c32
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_sqp.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_tools.h2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_uverbs.c2
-rw-r--r--drivers/infiniband/hw/ehca/hcp_if.c56
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c2
-rw-r--r--drivers/infiniband/hw/mlx4/main.c13
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c28
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c14
-rw-r--r--drivers/infiniband/hw/nes/nes_utils.c4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c65
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c5
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_vlan.c11
-rw-r--r--drivers/infiniband/ulp/iser/Kconfig2
-rw-r--r--drivers/input/keyboard/atkbd.c2
-rw-r--r--drivers/input/misc/Kconfig7
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/apanel.c81
-rw-r--r--drivers/input/misc/pcf50633-input.c132
-rw-r--r--drivers/input/mouse/pxa930_trkball.c4
-rw-r--r--drivers/input/touchscreen/da9034-ts.c1
-rw-r--r--drivers/isdn/hardware/eicon/debuglib.h2
-rw-r--r--drivers/isdn/hardware/eicon/os_4bri.c2
-rw-r--r--drivers/isdn/hardware/eicon/os_bri.c2
-rw-r--r--drivers/isdn/hardware/eicon/os_pri.c2
-rw-r--r--drivers/isdn/hardware/mISDN/Kconfig7
-rw-r--r--drivers/isdn/hardware/mISDN/Makefile1
-rw-r--r--drivers/isdn/hardware/mISDN/hfc_multi.h10
-rw-r--r--drivers/isdn/hardware/mISDN/hfc_pci.h2
-rw-r--r--drivers/isdn/hardware/mISDN/hfcmulti.c209
-rw-r--r--drivers/isdn/hardware/mISDN/hfcpci.c241
-rw-r--r--drivers/isdn/hardware/mISDN/hfcsusb.c2196
-rw-r--r--drivers/isdn/hardware/mISDN/hfcsusb.h418
-rw-r--r--drivers/isdn/hysdn/hysdn_net.c77
-rw-r--r--drivers/isdn/i4l/isdn_net.c70
-rw-r--r--drivers/isdn/mISDN/Makefile2
-rw-r--r--drivers/isdn/mISDN/clock.c216
-rw-r--r--drivers/isdn/mISDN/core.c280
-rw-r--r--drivers/isdn/mISDN/core.h2
-rw-r--r--drivers/isdn/mISDN/dsp.h2
-rw-r--r--drivers/isdn/mISDN/dsp_cmx.c149
-rw-r--r--drivers/isdn/mISDN/dsp_core.c55
-rw-r--r--drivers/isdn/mISDN/dsp_pipeline.c38
-rw-r--r--drivers/isdn/mISDN/hwchannel.c42
-rw-r--r--drivers/isdn/mISDN/l1oip_core.c25
-rw-r--r--drivers/isdn/mISDN/layer1.c2
-rw-r--r--drivers/isdn/mISDN/socket.c41
-rw-r--r--drivers/isdn/mISDN/stack.c66
-rw-r--r--drivers/isdn/mISDN/tei.c6
-rw-r--r--drivers/leds/Kconfig22
-rw-r--r--drivers/leds/Makefile3
-rw-r--r--drivers/leds/led-class.c24
-rw-r--r--drivers/leds/leds-alix2.c181
-rw-r--r--drivers/leds/leds-ams-delta.c33
-rw-r--r--drivers/leds/leds-clevo-mail.c21
-rw-r--r--drivers/leds/leds-fsg.c37
-rw-r--r--drivers/leds/leds-gpio.c36
-rw-r--r--drivers/leds/leds-hp-disk.c155
-rw-r--r--drivers/leds/leds-hp6xx.c22
-rw-r--r--drivers/leds/leds-net48xx.c21
-rw-r--r--drivers/leds/leds-pca9532.c77
-rw-r--r--drivers/leds/leds-s3c24xx.c25
-rw-r--r--drivers/leds/leds-wm8350.c311
-rw-r--r--drivers/leds/leds-wrap.c27
-rw-r--r--drivers/leds/ledtrig-timer.c5
-rw-r--r--drivers/macintosh/Kconfig2
-rw-r--r--drivers/md/bitmap.c11
-rw-r--r--drivers/md/faulty.c3
-rw-r--r--drivers/md/linear.c3
-rw-r--r--drivers/md/md.c416
-rw-r--r--drivers/md/multipath.c3
-rw-r--r--drivers/md/raid0.c178
-rw-r--r--drivers/md/raid1.c11
-rw-r--r--drivers/md/raid10.c3
-rw-r--r--drivers/md/raid5.c8
-rw-r--r--drivers/media/common/tuners/tda8290.c6
-rw-r--r--drivers/media/dvb/dm1105/Kconfig1
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c26
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c57
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.c2
-rw-r--r--drivers/media/dvb/frontends/cx24116.c2
-rw-r--r--drivers/media/dvb/frontends/lgdt3304.c10
-rw-r--r--drivers/media/dvb/frontends/s921_module.c2
-rw-r--r--drivers/media/dvb/frontends/stb0899_algo.c4
-rw-r--r--drivers/media/dvb/frontends/stb0899_drv.c6
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c4
-rw-r--r--drivers/media/video/cafe_ccic.c1
-rw-r--r--drivers/media/video/cx88/Kconfig5
-rw-r--r--drivers/media/video/cx88/Makefile3
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c46
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c24
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c30
-rw-r--r--drivers/media/video/cx88/cx88.h4
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c5
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c2
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.c2
-rw-r--r--drivers/media/video/ov7670.c1
-rw-r--r--drivers/media/video/ovcamchip/ovcamchip_core.c1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c2
-rw-r--r--drivers/media/video/pxa_camera.c4
-rw-r--r--drivers/media/video/pxa_camera.h95
-rw-r--r--drivers/media/video/usbvideo/ibmcam.c2
-rw-r--r--drivers/media/video/usbvideo/konicawc.c2
-rw-r--r--drivers/media/video/usbvideo/ultracam.c2
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c3
-rw-r--r--drivers/media/video/v4l2-device.c4
-rw-r--r--drivers/media/video/videobuf-dma-sg.c3
-rw-r--r--drivers/media/video/w9968cf.c1
-rw-r--r--drivers/memstick/core/mspro_block.c43
-rw-r--r--drivers/message/fusion/lsi/mpi.h7
-rw-r--r--drivers/message/fusion/lsi/mpi_cnfg.h47
-rw-r--r--drivers/message/fusion/lsi/mpi_fc.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_history.txt86
-rw-r--r--drivers/message/fusion/lsi/mpi_init.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_ioc.h22
-rw-r--r--drivers/message/fusion/lsi/mpi_lan.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_log_fc.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_log_sas.h37
-rw-r--r--drivers/message/fusion/lsi/mpi_raid.h11
-rw-r--r--drivers/message/fusion/lsi/mpi_sas.h18
-rw-r--r--drivers/message/fusion/lsi/mpi_targ.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_tool.h2
-rw-r--r--drivers/message/fusion/lsi/mpi_type.h4
-rw-r--r--drivers/message/fusion/mptbase.c87
-rw-r--r--drivers/message/fusion/mptbase.h3
-rw-r--r--drivers/message/fusion/mptctl.c5
-rw-r--r--drivers/message/fusion/mptlan.c44
-rw-r--r--drivers/message/fusion/mptscsih.c3
-rw-r--r--drivers/message/i2o/i2o_scsi.c2
-rw-r--r--drivers/mfd/Kconfig23
-rw-r--r--drivers/mfd/Makefile4
-rw-r--r--drivers/mfd/dm355evm_msp.c10
-rw-r--r--drivers/mfd/pcf50633-adc.c277
-rw-r--r--drivers/mfd/pcf50633-core.c710
-rw-r--r--drivers/mfd/pcf50633-gpio.c118
-rw-r--r--drivers/mfd/sm501.c30
-rw-r--r--drivers/mfd/twl4030-core.c11
-rw-r--r--drivers/mfd/wm8350-core.c3
-rw-r--r--drivers/misc/Kconfig296
-rw-r--r--drivers/misc/Makefile13
-rw-r--r--drivers/misc/enclosure.c8
-rw-r--r--drivers/misc/ibmasm/event.c2
-rw-r--r--drivers/misc/phantom.c2
-rw-r--r--drivers/misc/sgi-xp/xpc_sn2.c2
-rw-r--r--drivers/misc/sgi-xp/xpnet.c68
-rw-r--r--drivers/mmc/host/atmel-mci.c105
-rw-r--r--drivers/mtd/Kconfig10
-rw-r--r--drivers/mtd/Makefile2
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c12
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c18
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0020.c14
-rw-r--r--drivers/mtd/chips/fwh_lock.h4
-rw-r--r--drivers/mtd/devices/Kconfig7
-rw-r--r--drivers/mtd/devices/Makefile1
-rw-r--r--drivers/mtd/devices/lart.c6
-rw-r--r--drivers/mtd/devices/m25p80.c41
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c24
-rw-r--r--drivers/mtd/devices/pmc551.c2
-rw-r--r--drivers/mtd/devices/ps3vram.c768
-rw-r--r--drivers/mtd/ftl.c100
-rw-r--r--drivers/mtd/inftlcore.c2
-rw-r--r--drivers/mtd/inftlmount.c4
-rw-r--r--drivers/mtd/lpddr/Kconfig22
-rw-r--r--drivers/mtd/lpddr/Makefile6
-rw-r--r--drivers/mtd/lpddr/lpddr_cmds.c796
-rw-r--r--drivers/mtd/lpddr/qinfo_probe.c255
-rw-r--r--drivers/mtd/maps/Kconfig21
-rw-r--r--drivers/mtd/maps/alchemy-flash.c2
-rw-r--r--drivers/mtd/maps/amd76xrom.c4
-rw-r--r--drivers/mtd/maps/cfi_flagadm.c2
-rw-r--r--drivers/mtd/maps/ck804xrom.c4
-rw-r--r--drivers/mtd/maps/dbox2-flash.c2
-rw-r--r--drivers/mtd/maps/edb7312.c2
-rw-r--r--drivers/mtd/maps/esb2rom.c4
-rw-r--r--drivers/mtd/maps/fortunet.c2
-rw-r--r--drivers/mtd/maps/h720x-flash.c2
-rw-r--r--drivers/mtd/maps/ichxrom.c4
-rw-r--r--drivers/mtd/maps/impa7.c2
-rw-r--r--drivers/mtd/maps/ipaq-flash.c2
-rw-r--r--drivers/mtd/maps/mbx860.c2
-rw-r--r--drivers/mtd/maps/nettel.c9
-rw-r--r--drivers/mtd/maps/octagon-5066.c2
-rw-r--r--drivers/mtd/maps/physmap.c41
-rw-r--r--drivers/mtd/maps/pmcmsp-flash.c2
-rw-r--r--drivers/mtd/maps/redwood.c2
-rw-r--r--drivers/mtd/maps/rpxlite.c2
-rw-r--r--drivers/mtd/maps/sbc8240.c2
-rw-r--r--drivers/mtd/maps/scb2_flash.c8
-rw-r--r--drivers/mtd/maps/sharpsl-flash.c2
-rw-r--r--drivers/mtd/maps/tqm8xxl.c2
-rw-r--r--drivers/mtd/maps/uclinux.c4
-rw-r--r--drivers/mtd/maps/vmax301.c2
-rw-r--r--drivers/mtd/maps/wr_sbc82xx_flash.c2
-rw-r--r--drivers/mtd/mtdchar.c6
-rw-r--r--drivers/mtd/mtdconcat.c35
-rw-r--r--drivers/mtd/mtdcore.c16
-rw-r--r--drivers/mtd/mtdoops.c9
-rw-r--r--drivers/mtd/mtdpart.c34
-rw-r--r--drivers/mtd/nand/Kconfig7
-rw-r--r--drivers/mtd/nand/alauda.c6
-rw-r--r--drivers/mtd/nand/cafe_nand.c7
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c4
-rw-r--r--drivers/mtd/nand/nand_base.c25
-rw-r--r--drivers/mtd/nand/nand_bbt.c31
-rw-r--r--drivers/mtd/nand/nandsim.c339
-rw-r--r--drivers/mtd/nand/ndfc.c269
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c6
-rw-r--r--drivers/mtd/nand/sharpsl.c247
-rw-r--r--drivers/mtd/nftlcore.c2
-rw-r--r--drivers/mtd/nftlmount.c4
-rw-r--r--drivers/mtd/onenand/onenand_base.c8
-rw-r--r--drivers/mtd/rfd_ftl.c29
-rw-r--r--drivers/mtd/ssfdc.c7
-rw-r--r--drivers/mtd/tests/Makefile7
-rw-r--r--drivers/mtd/tests/mtd_oobtest.c742
-rw-r--r--drivers/mtd/tests/mtd_pagetest.c632
-rw-r--r--drivers/mtd/tests/mtd_readtest.c253
-rw-r--r--drivers/mtd/tests/mtd_speedtest.c502
-rw-r--r--drivers/mtd/tests/mtd_stresstest.c330
-rw-r--r--drivers/mtd/tests/mtd_subpagetest.c525
-rw-r--r--drivers/mtd/tests/mtd_torturetest.c530
-rw-r--r--drivers/mtd/ubi/build.c2
-rw-r--r--drivers/mtd/ubi/eba.c2
-rw-r--r--drivers/mtd/ubi/gluebi.c17
-rw-r--r--drivers/mtd/ubi/io.c2
-rw-r--r--drivers/mtd/ubi/kapi.c2
-rw-r--r--drivers/mtd/ubi/scan.c2
-rw-r--r--drivers/mtd/ubi/ubi-media.h4
-rw-r--r--drivers/mtd/ubi/vtbl.c2
-rw-r--r--drivers/mtd/ubi/wl.c4
-rw-r--r--drivers/net/3c503.c1
-rw-r--r--drivers/net/3c59x.c2
-rw-r--r--drivers/net/8139cp.c2
-rw-r--r--drivers/net/8139too.c2
-rw-r--r--drivers/net/8390.c1
-rw-r--r--drivers/net/8390p.c1
-rw-r--r--drivers/net/Kconfig6
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/acenic.c1
-rw-r--r--drivers/net/acenic_firmware.h9456
-rw-r--r--drivers/net/amd8111e.c35
-rw-r--r--drivers/net/appletalk/ipddp.c25
-rw-r--r--drivers/net/arm/etherh.c1
-rw-r--r--drivers/net/arm/ks8695net.c1
-rw-r--r--drivers/net/atp.c32
-rw-r--r--drivers/net/ax88796.c27
-rw-r--r--drivers/net/b44.c46
-rw-r--r--drivers/net/b44.h2
-rw-r--r--drivers/net/bnx2x.h19
-rw-r--r--drivers/net/bnx2x_link.c2
-rw-r--r--drivers/net/bnx2x_main.c181
-rw-r--r--drivers/net/bonding/bond_main.c2
-rw-r--r--drivers/net/cassini.c29
-rw-r--r--drivers/net/cxgb3/adapter.h7
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c22
-rw-r--r--drivers/net/cxgb3/sge.c2
-rw-r--r--drivers/net/de600.c14
-rw-r--r--drivers/net/de620.c17
-rw-r--r--drivers/net/e100.c299
-rw-r--r--drivers/net/e1000/e1000_hw.c4
-rw-r--r--drivers/net/e1000e/ich8lan.c19
-rw-r--r--drivers/net/e1000e/netdev.c2
-rw-r--r--drivers/net/e2100.c1
-rw-r--r--drivers/net/ehea/ehea_main.c8
-rw-r--r--drivers/net/ehea/ehea_phyp.c16
-rw-r--r--drivers/net/ehea/ehea_qmr.c18
-rw-r--r--drivers/net/enc28j60.c18
-rw-r--r--drivers/net/enic/enic_main.c1
-rw-r--r--drivers/net/epic100.c21
-rw-r--r--drivers/net/fealnx.c21
-rw-r--r--drivers/net/forcedeth.c22
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c1
-rw-r--r--drivers/net/gianfar.c31
-rw-r--r--drivers/net/hamachi.c1
-rw-r--r--drivers/net/hamradio/6pack.c3
-rw-r--r--drivers/net/hp-plus.c1
-rw-r--r--drivers/net/hp100.c32
-rw-r--r--drivers/net/hydra.c1
-rw-r--r--drivers/net/ibm_newemac/mal.c4
-rw-r--r--drivers/net/ibm_newemac/mal.h2
-rw-r--r--drivers/net/ibmveth.c20
-rw-r--r--drivers/net/ibmveth.h10
-rw-r--r--drivers/net/ipg.c23
-rw-r--r--drivers/net/irda/ali-ircc.c45
-rw-r--r--drivers/net/irda/ali-ircc.h1
-rw-r--r--drivers/net/irda/au1000_ircc.h1
-rw-r--r--drivers/net/irda/au1k_ir.c11
-rw-r--r--drivers/net/irda/donauboe.c8
-rw-r--r--drivers/net/irda/donauboe.h1
-rw-r--r--drivers/net/irda/irda-usb.c30
-rw-r--r--drivers/net/irda/irda-usb.h1
-rw-r--r--drivers/net/irda/kingsun-sir.c20
-rw-r--r--drivers/net/irda/ks959-sir.c22
-rw-r--r--drivers/net/irda/ksdazzle-sir.c26
-rw-r--r--drivers/net/irda/mcs7780.c49
-rw-r--r--drivers/net/irda/mcs7780.h2
-rw-r--r--drivers/net/irda/nsc-ircc.c45
-rw-r--r--drivers/net/irda/nsc-ircc.h1
-rw-r--r--drivers/net/irda/pxaficp_ir.c52
-rw-r--r--drivers/net/irda/sa1100_ir.c46
-rw-r--r--drivers/net/irda/sir-dev.h1
-rw-r--r--drivers/net/irda/sir_dev.c26
-rw-r--r--drivers/net/irda/smsc-ircc2.c38
-rw-r--r--drivers/net/irda/stir4200.c44
-rw-r--r--drivers/net/irda/via-ircc.c47
-rw-r--r--drivers/net/irda/via-ircc.h1
-rw-r--r--drivers/net/irda/vlsi_ir.c78
-rw-r--r--drivers/net/irda/vlsi_ir.h1
-rw-r--r--drivers/net/irda/w83977af_ir.c35
-rw-r--r--drivers/net/irda/w83977af_ir.h1
-rw-r--r--drivers/net/iseries_veth.c2
-rw-r--r--drivers/net/korina.c158
-rw-r--r--drivers/net/mac8390.c1
-rw-r--r--drivers/net/mlx4/en_netdev.c1
-rw-r--r--drivers/net/mlx4/en_params.c6
-rw-r--r--drivers/net/mlx4/en_tx.c59
-rw-r--r--drivers/net/mlx4/main.c4
-rw-r--r--drivers/net/mlx4/mlx4_en.h5
-rw-r--r--drivers/net/mlx4/profile.c6
-rw-r--r--drivers/net/natsemi.c29
-rw-r--r--drivers/net/ne-h8300.c1
-rw-r--r--drivers/net/ne2k-pci.c1
-rw-r--r--drivers/net/netxen/netxen_nic.h146
-rw-r--r--drivers/net/netxen/netxen_nic_ctx.c50
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c31
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c97
-rw-r--r--drivers/net/netxen/netxen_nic_init.c105
-rw-r--r--drivers/net/netxen/netxen_nic_main.c210
-rw-r--r--drivers/net/ns83820.c5
-rw-r--r--drivers/net/pasemi_mac.c6
-rw-r--r--drivers/net/pcnet32.c32
-rw-r--r--drivers/net/phy/phy_device.c9
-rw-r--r--drivers/net/plip.c13
-rw-r--r--drivers/net/ppp_generic.c43
-rw-r--r--drivers/net/qlge/qlge.h61
-rw-r--r--drivers/net/qlge/qlge_dbg.c62
-rw-r--r--drivers/net/qlge/qlge_main.c80
-rw-r--r--drivers/net/r6040.c62
-rw-r--r--drivers/net/sb1000.c16
-rw-r--r--drivers/net/sc92031.c1
-rw-r--r--drivers/net/sfc/falcon.c4
-rw-r--r--drivers/net/sfc/tenxpress.c5
-rw-r--r--drivers/net/sis190.c28
-rw-r--r--drivers/net/sis900.c9
-rw-r--r--drivers/net/slip.c28
-rw-r--r--drivers/net/slip.h2
-rw-r--r--drivers/net/smc-mca.c1
-rw-r--r--drivers/net/smc-ultra.c1
-rw-r--r--drivers/net/smsc911x.c4
-rw-r--r--drivers/net/smsc9420.c1
-rw-r--r--drivers/net/starfire.c34
-rw-r--r--drivers/net/sundance.c23
-rw-r--r--drivers/net/sungem.c22
-rw-r--r--drivers/net/sunhme.c26
-rw-r--r--drivers/net/sunvnet.c8
-rw-r--r--drivers/net/tehuti.c4
-rw-r--r--drivers/net/tlan.c26
-rw-r--r--drivers/net/tokenring/smctr.c2
-rw-r--r--drivers/net/tulip/de2104x.c19
-rw-r--r--drivers/net/tulip/de4x5.c20
-rw-r--r--drivers/net/tulip/dmfe.c62
-rw-r--r--drivers/net/tulip/tulip_core.c27
-rw-r--r--drivers/net/tulip/uli526x.c63
-rw-r--r--drivers/net/tulip/winbond-840.c23
-rw-r--r--drivers/net/tulip/xircom_cb.c43
-rw-r--r--drivers/net/typhoon.c22
-rw-r--r--drivers/net/ucc_geth.c128
-rw-r--r--drivers/net/ucc_geth.h114
-rw-r--r--drivers/net/usb/dm9601.c29
-rw-r--r--drivers/net/usb/hso.c12
-rw-r--r--drivers/net/usb/kaweth.c29
-rw-r--r--drivers/net/usb/pegasus.c33
-rw-r--r--drivers/net/via-rhine.c1
-rw-r--r--drivers/net/via-velocity.c1
-rw-r--r--drivers/net/virtio_net.c20
-rw-r--r--drivers/net/wan/ixp4xx_hss.c6
-rw-r--r--drivers/net/wd.c1
-rw-r--r--drivers/net/wimax/Kconfig17
-rw-r--r--drivers/net/wimax/Makefile5
-rw-r--r--drivers/net/wimax/i2400m/Kconfig49
-rw-r--r--drivers/net/wimax/i2400m/Makefile29
-rw-r--r--drivers/net/wimax/i2400m/control.c1291
-rw-r--r--drivers/net/wimax/i2400m/debug-levels.h45
-rw-r--r--drivers/net/wimax/i2400m/debugfs.c392
-rw-r--r--drivers/net/wimax/i2400m/driver.c728
-rw-r--r--drivers/net/wimax/i2400m/fw.c1095
-rw-r--r--drivers/net/wimax/i2400m/i2400m-sdio.h132
-rw-r--r--drivers/net/wimax/i2400m/i2400m-usb.h264
-rw-r--r--drivers/net/wimax/i2400m/i2400m.h755
-rw-r--r--drivers/net/wimax/i2400m/netdev.c524
-rw-r--r--drivers/net/wimax/i2400m/op-rfkill.c207
-rw-r--r--drivers/net/wimax/i2400m/rx.c534
-rw-r--r--drivers/net/wimax/i2400m/sdio-debug-levels.h22
-rw-r--r--drivers/net/wimax/i2400m/sdio-fw.c224
-rw-r--r--drivers/net/wimax/i2400m/sdio-rx.c255
-rw-r--r--drivers/net/wimax/i2400m/sdio-tx.c153
-rw-r--r--drivers/net/wimax/i2400m/sdio.c511
-rw-r--r--drivers/net/wimax/i2400m/tx.c817
-rw-r--r--drivers/net/wimax/i2400m/usb-debug-levels.h42
-rw-r--r--drivers/net/wimax/i2400m/usb-fw.c340
-rw-r--r--drivers/net/wimax/i2400m/usb-notif.c269
-rw-r--r--drivers/net/wimax/i2400m/usb-rx.c417
-rw-r--r--drivers/net/wimax/i2400m/usb-tx.c229
-rw-r--r--drivers/net/wimax/i2400m/usb.c597
-rw-r--r--drivers/net/wireless/Kconfig2
-rw-r--r--drivers/net/wireless/ath5k/base.c8
-rw-r--r--drivers/net/wireless/ath5k/dma.c2
-rw-r--r--drivers/net/wireless/ath5k/pcu.c4
-rw-r--r--drivers/net/wireless/ath5k/reg.h2
-rw-r--r--drivers/net/wireless/ath9k/Kconfig1
-rw-r--r--drivers/net/wireless/ath9k/main.c4
-rw-r--r--drivers/net/wireless/ath9k/xmit.c48
-rw-r--r--drivers/net/wireless/atmel.c2
-rw-r--r--drivers/net/wireless/b43/main.c2
-rw-r--r--drivers/net/wireless/b43legacy/main.c2
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c1
-rw-r--r--drivers/net/wireless/libertas/main.c7
-rw-r--r--drivers/net/wireless/libertas_tf/main.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco.c28
-rw-r--r--drivers/net/wireless/orinoco/orinoco_cs.c1
-rw-r--r--drivers/net/wireless/p54/p54common.c34
-rw-r--r--drivers/net/wireless/p54/p54usb.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c23
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00crypto.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00leds.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h11
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c6
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c1
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_dev.c1
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c5
-rw-r--r--drivers/net/wireless/strip.c2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c2
-rw-r--r--drivers/net/xen-netfront.c17
-rw-r--r--drivers/net/yellowfin.c1
-rw-r--r--drivers/net/zorro8390.c1
-rw-r--r--drivers/of/of_i2c.c19
-rw-r--r--drivers/oprofile/buffer_sync.c188
-rw-r--r--drivers/oprofile/cpu_buffer.c316
-rw-r--r--drivers/oprofile/cpu_buffer.h89
-rw-r--r--drivers/oprofile/event_buffer.c4
-rw-r--r--drivers/oprofile/oprof.c4
-rw-r--r--drivers/oprofile/oprof.h8
-rw-r--r--drivers/oprofile/oprofile_files.c27
-rw-r--r--drivers/parisc/asp.c3
-rw-r--r--drivers/parisc/ccio-dma.c4
-rw-r--r--drivers/parisc/dino.c8
-rw-r--r--drivers/parisc/hppb.c2
-rw-r--r--drivers/parisc/iosapic.c3
-rw-r--r--drivers/parisc/lasi.c5
-rw-r--r--drivers/parisc/lba_pci.c2
-rw-r--r--drivers/parisc/sba_iommu.c9
-rw-r--r--drivers/parisc/superio.c1
-rw-r--r--drivers/parisc/wax.c3
-rw-r--r--drivers/pci/Kconfig9
-rw-r--r--drivers/pci/Makefile2
-rw-r--r--drivers/pci/access.c226
-rw-r--r--drivers/pci/bus.c87
-rw-r--r--drivers/pci/hotplug/Makefile3
-rw-r--r--drivers/pci/hotplug/acpi_pcihp.c70
-rw-r--r--drivers/pci/hotplug/acpiphp.h2
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c119
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c2
-rw-r--r--drivers/pci/hotplug/cpqphp_ctrl.c6
-rw-r--r--drivers/pci/hotplug/cpqphp_pci.c2
-rw-r--r--drivers/pci/hotplug/fakephp.c1
-rw-r--r--drivers/pci/hotplug/pciehp.h16
-rw-r--r--drivers/pci/hotplug/pciehp_acpi.c141
-rw-r--r--drivers/pci/hotplug/pciehp_core.c1
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c26
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c329
-rw-r--r--drivers/pci/intel-iommu.c3
-rw-r--r--drivers/pci/irq.c2
-rw-r--r--drivers/pci/msi.c31
-rw-r--r--drivers/pci/pci-acpi.c84
-rw-r--r--drivers/pci/pci-driver.c420
-rw-r--r--drivers/pci/pci-stub.c47
-rw-r--r--drivers/pci/pci-sysfs.c107
-rw-r--r--drivers/pci/pci.c505
-rw-r--r--drivers/pci/pci.h34
-rw-r--r--drivers/pci/pcie/aer/aerdrv_acpi.c1
-rw-r--r--drivers/pci/pcie/aer/aerdrv_errprint.c2
-rw-r--r--drivers/pci/pcie/aspm.c165
-rw-r--r--drivers/pci/pcie/portdrv_bus.c32
-rw-r--r--drivers/pci/pcie/portdrv_core.c240
-rw-r--r--drivers/pci/pcie/portdrv_pci.c21
-rw-r--r--drivers/pci/probe.c48
-rw-r--r--drivers/pci/proc.c18
-rw-r--r--drivers/pci/quirks.c112
-rw-r--r--drivers/pci/setup-bus.c5
-rw-r--r--drivers/pci/setup-res.c24
-rw-r--r--drivers/pci/syscall.c12
-rw-r--r--drivers/pcmcia/electra_cf.c2
-rw-r--r--drivers/platform/Kconfig5
-rw-r--r--drivers/platform/Makefile5
-rw-r--r--drivers/platform/x86/Kconfig398
-rw-r--r--drivers/platform/x86/Makefile20
-rw-r--r--drivers/platform/x86/acer-wmi.c (renamed from drivers/misc/acer-wmi.c)0
-rw-r--r--drivers/platform/x86/asus-laptop.c (renamed from drivers/misc/asus-laptop.c)0
-rw-r--r--drivers/platform/x86/asus_acpi.c (renamed from drivers/acpi/asus_acpi.c)0
-rw-r--r--drivers/platform/x86/compal-laptop.c (renamed from drivers/misc/compal-laptop.c)0
-rw-r--r--drivers/platform/x86/dell-laptop.c436
-rw-r--r--drivers/platform/x86/eeepc-laptop.c (renamed from drivers/misc/eeepc-laptop.c)4
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c (renamed from drivers/misc/fujitsu-laptop.c)419
-rw-r--r--drivers/platform/x86/hp-wmi.c (renamed from drivers/misc/hp-wmi.c)15
-rw-r--r--drivers/platform/x86/intel_menlow.c (renamed from drivers/misc/intel_menlow.c)0
-rw-r--r--drivers/platform/x86/msi-laptop.c (renamed from drivers/misc/msi-laptop.c)0
-rw-r--r--drivers/platform/x86/panasonic-laptop.c (renamed from drivers/misc/panasonic-laptop.c)22
-rw-r--r--drivers/platform/x86/sony-laptop.c (renamed from drivers/misc/sony-laptop.c)15
-rw-r--r--drivers/platform/x86/tc1100-wmi.c (renamed from drivers/misc/tc1100-wmi.c)1
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c (renamed from drivers/misc/thinkpad_acpi.c)911
-rw-r--r--drivers/platform/x86/toshiba_acpi.c (renamed from drivers/acpi/toshiba_acpi.c)0
-rw-r--r--drivers/platform/x86/wmi.c (renamed from drivers/acpi/wmi.c)0
-rw-r--r--drivers/pnp/pnpacpi/core.c1
-rw-r--r--drivers/power/Kconfig6
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/pcf50633-charger.c358
-rw-r--r--drivers/ps3/ps3-lpm.c16
-rw-r--r--drivers/ps3/ps3-vuart.c32
-rw-r--r--drivers/ps3/ps3stor_lib.c14
-rw-r--r--drivers/regulator/Kconfig7
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/core.c474
-rw-r--r--drivers/regulator/da903x.c12
-rw-r--r--drivers/regulator/pcf50633-regulator.c329
-rw-r--r--drivers/regulator/wm8350-regulator.c91
-rw-r--r--drivers/regulator/wm8400-regulator.c2
-rw-r--r--drivers/rtc/Kconfig7
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-ds1307.c154
-rw-r--r--drivers/rtc/rtc-ds1511.c2
-rw-r--r--drivers/rtc/rtc-parisc.c3
-rw-r--r--drivers/rtc/rtc-pcf50633.c344
-rw-r--r--drivers/rtc/rtc-pxa.c2
-rw-r--r--drivers/rtc/rtc-stk17ta8.c2
-rw-r--r--drivers/rtc/rtc-twl4030.c49
-rw-r--r--drivers/s390/block/dasd.c21
-rw-r--r--drivers/s390/block/dasd_3990_erp.c2
-rw-r--r--drivers/s390/block/dasd_devmap.c48
-rw-r--r--drivers/s390/block/dasd_diag.c3
-rw-r--r--drivers/s390/block/dasd_eckd.c3
-rw-r--r--drivers/s390/block/dasd_eer.c4
-rw-r--r--drivers/s390/block/dasd_fba.c3
-rw-r--r--drivers/s390/block/dasd_int.h2
-rw-r--r--drivers/s390/char/Kconfig2
-rw-r--r--drivers/s390/char/tape_3590.c2
-rw-r--r--drivers/s390/char/vmlogrdr.c4
-rw-r--r--drivers/s390/cio/cio.c2
-rw-r--r--drivers/s390/cio/qdio_debug.c2
-rw-r--r--drivers/s390/cio/qdio_main.c2
-rw-r--r--drivers/s390/net/qeth_l2_main.c27
-rw-r--r--drivers/s390/net/qeth_l3_main.c69
-rw-r--r--drivers/sbus/char/display7seg.c2
-rw-r--r--drivers/scsi/Kconfig1
-rw-r--r--drivers/scsi/NCR_D700.c2
-rw-r--r--drivers/scsi/a100u2w.c2
-rw-r--r--drivers/scsi/a2091.c18
-rw-r--r--drivers/scsi/advansys.c2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_tmf.c2
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_ddp.c1
-rw-r--r--drivers/scsi/gvp11.c8
-rw-r--r--drivers/scsi/hosts.c6
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c28
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.h6
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c28
-rw-r--r--drivers/scsi/ipr.c4
-rw-r--r--drivers/scsi/ipr.h2
-rw-r--r--drivers/scsi/lasi700.c3
-rw-r--r--drivers/scsi/libiscsi_tcp.c3
-rw-r--r--drivers/scsi/libsas/sas_discover.c2
-rw-r--r--drivers/scsi/libsas/sas_dump.c2
-rw-r--r--drivers/scsi/libsas/sas_host_smp.c12
-rw-r--r--drivers/scsi/libsas/sas_port.c2
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c4
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c3
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c10
-rw-r--r--drivers/scsi/megaraid.c4
-rw-r--r--drivers/scsi/mvsas.c2
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c2
-rw-r--r--drivers/scsi/ps3rom.c6
-rw-r--r--drivers/scsi/qla1280.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c26
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c462
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h40
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h33
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h294
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h10
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c9
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c353
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c12
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c82
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c41
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c5
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c146
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c263
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h6
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c2
-rw-r--r--drivers/scsi/raid_class.c3
-rw-r--r--drivers/scsi/scsi.c9
-rw-r--r--drivers/scsi/scsi_debug.c4
-rw-r--r--drivers/scsi/scsi_devinfo.c1
-rw-r--r--drivers/scsi/scsi_error.c26
-rw-r--r--drivers/scsi/scsi_ioctl.c9
-rw-r--r--drivers/scsi/scsi_lib.c119
-rw-r--r--drivers/scsi/scsi_scan.c10
-rw-r--r--drivers/scsi/scsi_sysfs.c12
-rw-r--r--drivers/scsi/scsi_transport_fc.c39
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c11
-rw-r--r--drivers/scsi/scsi_transport_sas.c42
-rw-r--r--drivers/scsi/scsi_transport_srp.c2
-rw-r--r--drivers/scsi/sd.c109
-rw-r--r--drivers/scsi/sd_dif.c17
-rw-r--r--drivers/scsi/ses.c2
-rw-r--r--drivers/scsi/sg.c2
-rw-r--r--drivers/scsi/sgiwd93.c3
-rw-r--r--drivers/scsi/sim710.c4
-rw-r--r--drivers/scsi/sni_53c710.c3
-rw-r--r--drivers/scsi/st.c492
-rw-r--r--drivers/scsi/st.h14
-rw-r--r--drivers/scsi/zalon.c4
-rw-r--r--drivers/serial/8250.c4
-rw-r--r--drivers/serial/8250_pci.c8
-rw-r--r--drivers/serial/8250_pnp.c2
-rw-r--r--drivers/serial/Kconfig21
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/atmel_serial.c2
-rw-r--r--drivers/serial/crisv10.c4
-rw-r--r--drivers/serial/jsm/jsm_neo.c3
-rw-r--r--drivers/serial/nwpserial.c475
-rw-r--r--drivers/serial/of_serial.c20
-rw-r--r--drivers/serial/pnx8xxx_uart.c23
-rw-r--r--drivers/spi/atmel_spi.c3
-rw-r--r--drivers/spi/spi_lm70llp.c33
-rw-r--r--drivers/spi/xilinx_spi.c137
-rw-r--r--drivers/staging/comedi/drivers.c2
-rw-r--r--drivers/staging/epl/Edrv8139.c60
-rw-r--r--drivers/staging/epl/EplSdoAsySequ.c2
-rw-r--r--drivers/staging/frontier/alphatrack.c12
-rw-r--r--drivers/staging/frontier/tranzport.c22
-rw-r--r--drivers/staging/go7007/go7007-v4l2.c3
-rw-r--r--drivers/staging/meilhaus/me0600_ext_irq.c4
-rw-r--r--drivers/staging/meilhaus/me1400_ext_irq.c2
-rw-r--r--drivers/staging/meilhaus/me1600_ao.c4
-rw-r--r--drivers/staging/meilhaus/me4600_ai.c8
-rw-r--r--drivers/staging/meilhaus/me4600_ao.c6
-rw-r--r--drivers/staging/meilhaus/me4600_ext_irq.c2
-rw-r--r--drivers/staging/meilhaus/me6000_ao.c20
-rw-r--r--drivers/staging/meilhaus/me8100_di.c6
-rw-r--r--drivers/staging/meilhaus/me8200_di.c4
-rw-r--r--drivers/staging/meilhaus/me8200_do.c2
-rw-r--r--drivers/staging/meilhaus/medebug.h10
-rw-r--r--drivers/staging/otus/80211core/cagg.c2
-rw-r--r--drivers/staging/otus/80211core/pub_zfw.h2
-rw-r--r--drivers/staging/otus/80211core/struct.h2
-rw-r--r--drivers/staging/otus/oal_marc.h12
-rw-r--r--drivers/staging/rt2860/2860_main_dev.c2
-rw-r--r--drivers/staging/rt2860/common/ba_action.c18
-rw-r--r--drivers/staging/rt2860/common/cmm_data.c2
-rw-r--r--drivers/staging/rt2860/common/cmm_data_2860.c6
-rw-r--r--drivers/staging/rt2860/common/cmm_info.c2
-rw-r--r--drivers/staging/rt2860/common/dfs.c4
-rw-r--r--drivers/staging/rt2860/common/rtmp_init.c18
-rw-r--r--drivers/staging/rt2860/common/spectrum.c44
-rw-r--r--drivers/staging/rt2860/rt_ate.c32
-rw-r--r--drivers/staging/rt2860/rt_linux.c18
-rw-r--r--drivers/staging/rt2860/rt_linux.h2
-rw-r--r--drivers/staging/rt2860/rt_profile.c12
-rw-r--r--drivers/staging/rt2860/rtmp_def.h2
-rw-r--r--drivers/staging/rt2860/sta_ioctl.c36
-rw-r--r--drivers/staging/rt2870/2870_main_dev.c6
-rw-r--r--drivers/staging/rt2870/common/2870_rtmp_init.c4
-rw-r--r--drivers/staging/rt2870/common/ba_action.c18
-rw-r--r--drivers/staging/rt2870/common/cmm_data.c2
-rw-r--r--drivers/staging/rt2870/common/cmm_info.c2
-rw-r--r--drivers/staging/rt2870/common/dfs.c4
-rw-r--r--drivers/staging/rt2870/common/rtmp_init.c20
-rw-r--r--drivers/staging/rt2870/common/rtusb_bulk.c4
-rw-r--r--drivers/staging/rt2870/common/spectrum.c44
-rw-r--r--drivers/staging/rt2870/rt_ate.c30
-rw-r--r--drivers/staging/rt2870/rt_linux.c18
-rw-r--r--drivers/staging/rt2870/rt_linux.h2
-rw-r--r--drivers/staging/rt2870/rt_main_dev.c2
-rw-r--r--drivers/staging/rt2870/rt_profile.c12
-rw-r--r--drivers/staging/rt2870/rtmp_def.h2
-rw-r--r--drivers/staging/rt2870/sta_ioctl.c36
-rw-r--r--drivers/staging/rt2870/tmp6036
-rw-r--r--drivers/staging/rt2870/tmp6136
-rw-r--r--drivers/staging/rtl8187se/ieee80211.h2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211.h2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c8
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c8
-rw-r--r--drivers/staging/rtl8187se/r8180_core.c12
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8225z2.c4
-rw-r--r--drivers/staging/rtl8187se/r8180_wx.c14
-rw-r--r--drivers/usb/Kconfig2
-rw-r--r--drivers/usb/class/cdc-acm.c2
-rw-r--r--drivers/usb/class/cdc-wdm.c3
-rw-r--r--drivers/usb/class/usbtmc.c9
-rw-r--r--drivers/usb/core/devio.c7
-rw-r--r--drivers/usb/core/driver.c181
-rw-r--r--drivers/usb/core/endpoint.c4
-rw-r--r--drivers/usb/core/generic.c10
-rw-r--r--drivers/usb/core/hcd-pci.c201
-rw-r--r--drivers/usb/core/hcd.c20
-rw-r--r--drivers/usb/core/hcd.h16
-rw-r--r--drivers/usb/core/hub.c144
-rw-r--r--drivers/usb/core/message.c164
-rw-r--r--drivers/usb/core/sysfs.c49
-rw-r--r--drivers/usb/core/urb.c43
-rw-r--r--drivers/usb/core/usb.c79
-rw-r--r--drivers/usb/core/usb.h24
-rw-r--r--drivers/usb/gadget/Kconfig43
-rw-r--r--drivers/usb/gadget/Makefile2
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.c2830
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.h195
-rw-r--r--drivers/usb/gadget/epautoconf.c2
-rw-r--r--drivers/usb/gadget/f_phonet.c12
-rw-r--r--drivers/usb/gadget/file_storage.c177
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c12
-rw-r--r--drivers/usb/gadget/gadget_chips.h8
-rw-r--r--drivers/usb/gadget/goku_udc.c2
-rw-r--r--drivers/usb/gadget/imx_udc.c1516
-rw-r--r--drivers/usb/gadget/imx_udc.h344
-rw-r--r--drivers/usb/gadget/m66592-udc.c9
-rw-r--r--drivers/usb/gadget/net2280.c2
-rw-r--r--drivers/usb/gadget/omap_udc.c4
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c2
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c2
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c34
-rw-r--r--drivers/usb/gadget/u_ether.c16
-rw-r--r--drivers/usb/host/Kconfig13
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-dbg.c8
-rw-r--r--drivers/usb/host/ehci-hub.c27
-rw-r--r--drivers/usb/host/ehci-pci.c12
-rw-r--r--drivers/usb/host/ehci-ppc-of.c45
-rw-r--r--drivers/usb/host/ehci.h34
-rw-r--r--drivers/usb/host/isp1760-hcd.c13
-rw-r--r--drivers/usb/host/isp1760-hcd.h1
-rw-r--r--drivers/usb/host/isp1760-if.c116
-rw-r--r--drivers/usb/host/ohci-hcd.c12
-rw-r--r--drivers/usb/host/ohci-pci.c6
-rw-r--r--drivers/usb/host/ohci-pnx4008.c85
-rw-r--r--drivers/usb/host/ohci-ppc-of.c25
-rw-r--r--drivers/usb/host/ohci-tmio.c2
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c3985
-rw-r--r--drivers/usb/host/oxu210hp.h447
-rw-r--r--drivers/usb/host/pci-quirks.c14
-rw-r--r--drivers/usb/host/r8a66597-hcd.c8
-rw-r--r--drivers/usb/host/uhci-hcd.c2
-rw-r--r--drivers/usb/image/microtek.c11
-rw-r--r--drivers/usb/misc/berry_charge.c5
-rw-r--r--drivers/usb/misc/emi26.c2
-rw-r--r--drivers/usb/misc/usbtest.c2
-rw-r--r--drivers/usb/mon/Kconfig13
-rw-r--r--drivers/usb/mon/Makefile3
-rw-r--r--drivers/usb/musb/Kconfig12
-rw-r--r--drivers/usb/musb/Makefile8
-rw-r--r--drivers/usb/musb/blackfin.c320
-rw-r--r--drivers/usb/musb/blackfin.h52
-rw-r--r--drivers/usb/musb/davinci.c18
-rw-r--r--drivers/usb/musb/musb_core.c84
-rw-r--r--drivers/usb/musb/musb_core.h73
-rw-r--r--drivers/usb/musb/musb_gadget.c2
-rw-r--r--drivers/usb/musb/musb_host.c45
-rw-r--r--drivers/usb/musb/musb_io.h26
-rw-r--r--drivers/usb/musb/musb_regs.h397
-rw-r--r--drivers/usb/musb/musbhsdma.c84
-rw-r--r--drivers/usb/musb/musbhsdma.h149
-rw-r--r--drivers/usb/musb/omap2430.c15
-rw-r--r--drivers/usb/musb/tusb6010.c7
-rw-r--r--drivers/usb/otg/Kconfig54
-rw-r--r--drivers/usb/otg/Makefile15
-rw-r--r--drivers/usb/otg/gpio_vbus.c335
-rw-r--r--drivers/usb/otg/isp1301_omap.c (renamed from drivers/i2c/chips/isp1301_omap.c)0
-rw-r--r--drivers/usb/otg/otg.c65
-rw-r--r--drivers/usb/otg/twl4030-usb.c721
-rw-r--r--drivers/usb/serial/Kconfig17
-rw-r--r--drivers/usb/serial/Makefile2
-rw-r--r--drivers/usb/serial/digi_acceleport.c28
-rw-r--r--drivers/usb/serial/ftdi_sio.c2
-rw-r--r--drivers/usb/serial/garmin_gps.c2
-rw-r--r--drivers/usb/serial/ipw.c4
-rw-r--r--drivers/usb/serial/iuu_phoenix.c38
-rw-r--r--drivers/usb/serial/mos7840.c38
-rw-r--r--drivers/usb/serial/opticon.c358
-rw-r--r--drivers/usb/serial/option.c11
-rw-r--r--drivers/usb/serial/siemens_mpi.c77
-rw-r--r--drivers/usb/serial/spcp8x5.c20
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c73
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.h8
-rw-r--r--drivers/usb/serial/usb-serial.c3
-rw-r--r--drivers/usb/serial/usb_debug.c2
-rw-r--r--drivers/usb/storage/Kconfig11
-rw-r--r--drivers/usb/storage/Makefile3
-rw-r--r--drivers/usb/storage/dpcm.c86
-rw-r--r--drivers/usb/storage/dpcm.h32
-rw-r--r--drivers/usb/storage/libusual.c7
-rw-r--r--drivers/usb/storage/option_ms.c147
-rw-r--r--drivers/usb/storage/option_ms.h4
-rw-r--r--drivers/usb/storage/protocol.c24
-rw-r--r--drivers/usb/storage/protocol.h3
-rw-r--r--drivers/usb/storage/scsiglue.c43
-rw-r--r--drivers/usb/storage/sddr09.c43
-rw-r--r--drivers/usb/storage/sddr09.h5
-rw-r--r--drivers/usb/storage/transport.c219
-rw-r--r--drivers/usb/storage/transport.h2
-rw-r--r--drivers/usb/storage/unusual_devs.h354
-rw-r--r--drivers/usb/storage/usb.c106
-rw-r--r--drivers/usb/storage/usb.h5
-rw-r--r--drivers/usb/wusbcore/rh.c2
-rw-r--r--drivers/uwb/i1480/dfu/usb.c2
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h2
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/lc.c17
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/netdev.c9
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/rx.c8
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/tx.c6
-rw-r--r--drivers/video/Makefile4
-rw-r--r--drivers/video/amba-clcd.c1
-rw-r--r--drivers/video/amifb.c6
-rw-r--r--drivers/video/atafb.c112
-rw-r--r--drivers/video/backlight/Kconfig15
-rw-r--r--drivers/video/backlight/Makefile2
-rw-r--r--drivers/video/backlight/backlight.c73
-rw-r--r--drivers/video/backlight/corgi_bl.c169
-rw-r--r--drivers/video/backlight/cr_bllcd.c18
-rw-r--r--drivers/video/backlight/generic_bl.c147
-rw-r--r--drivers/video/backlight/hp680_bl.c20
-rw-r--r--drivers/video/backlight/mbp_nvidia_bl.c1
-rw-r--r--drivers/video/backlight/progear_bl.c20
-rw-r--r--drivers/video/backlight/tdo24m.c94
-rw-r--r--drivers/video/backlight/tosa_lcd.c27
-rw-r--r--drivers/video/backlight/vgg2432a4.c2
-rw-r--r--drivers/video/bf54x-lq043fb.c15
-rw-r--r--drivers/video/bfin-t350mcqb-fb.c15
-rw-r--r--drivers/video/c2p.c232
-rw-r--r--drivers/video/c2p.h11
-rw-r--r--drivers/video/c2p_core.h153
-rw-r--r--drivers/video/c2p_iplan2.c153
-rw-r--r--drivers/video/c2p_planar.c156
-rw-r--r--drivers/video/console/fbcon.c38
-rw-r--r--drivers/video/console/vgacon.c2
-rw-r--r--drivers/video/ps3fb.c4
-rw-r--r--drivers/w1/masters/Kconfig6
-rw-r--r--drivers/w1/masters/Makefile2
-rw-r--r--drivers/w1/masters/mxc_w1.c211
-rw-r--r--drivers/w1/w1.h1
-rw-r--r--drivers/w1/w1_io.c26
-rw-r--r--drivers/w1/w1_netlink.c261
-rw-r--r--drivers/w1/w1_netlink.h16
-rw-r--r--drivers/watchdog/Kconfig14
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/gef_wdt.c330
-rw-r--r--drivers/watchdog/pika_wdt.c301
-rw-r--r--drivers/watchdog/wm8350_wdt.c6
-rw-r--r--drivers/xen/Kconfig24
-rw-r--r--drivers/xen/Makefile2
-rw-r--r--drivers/xen/xenbus/xenbus_client.c3
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c28
-rw-r--r--drivers/xen/xenbus/xenbus_xs.c1
-rw-r--r--drivers/xen/xenfs/Makefile3
-rw-r--r--drivers/xen/xenfs/super.c64
-rw-r--r--drivers/xen/xenfs/xenbus.c593
-rw-r--r--drivers/xen/xenfs/xenfs.h6
-rw-r--r--drivers/zorro/.gitignore2
-rw-r--r--drivers/zorro/zorro-sysfs.c20
-rw-r--r--drivers/zorro/zorro.c23
-rw-r--r--drivers/zorro/zorro.h2
1234 files changed, 68448 insertions, 24539 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 2f557f570ade..00cf9553f740 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -107,4 +107,6 @@ source "drivers/uio/Kconfig"
source "drivers/xen/Kconfig"
source "drivers/staging/Kconfig"
+
+source "drivers/platform/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index fceb71a741c3..c1bf41737936 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -18,6 +18,9 @@ obj-$(CONFIG_ARM_AMBA) += amba/
obj-$(CONFIG_XEN) += xen/
+# regulators early, since some subsystems rely on them to initialize
+obj-$(CONFIG_REGULATOR) += regulator/
+
# char/ comes before serial/ etc so that the VT console is the boot-time
# default.
obj-y += char/
@@ -57,6 +60,7 @@ obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
obj-$(CONFIG_PARIDE) += block/paride/
obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_UWB) += uwb/
+obj-$(CONFIG_USB_OTG_UTILS) += usb/otg/
obj-$(CONFIG_USB) += usb/
obj-$(CONFIG_USB_MUSB_HDRC) += usb/musb/
obj-$(CONFIG_PCI) += usb/
@@ -100,5 +104,5 @@ obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_OF) += of/
obj-$(CONFIG_SSB) += ssb/
obj-$(CONFIG_VIRTIO) += virtio/
-obj-$(CONFIG_REGULATOR) += regulator/
obj-$(CONFIG_STAGING) += staging/
+obj-y += platform/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index b0243fd55ac0..d7f9839ba264 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -196,90 +196,6 @@ config ACPI_NUMA
depends on (X86 || IA64)
default y if IA64_GENERIC || IA64_SGI_SN2
-config ACPI_WMI
- tristate "WMI (EXPERIMENTAL)"
- depends on X86
- depends on EXPERIMENTAL
- help
- This driver adds support for the ACPI-WMI (Windows Management
- Instrumentation) mapper device (PNP0C14) found on some systems.
-
- ACPI-WMI is a proprietary extension to ACPI to expose parts of the
- ACPI firmware to userspace - this is done through various vendor
- defined methods and data blocks in a PNP0C14 device, which are then
- made available for userspace to call.
-
- The implementation of this in Linux currently only exposes this to
- other kernel space drivers.
-
- This driver is a required dependency to build the firmware specific
- drivers needed on many machines, including Acer and HP laptops.
-
- It is safe to enable this driver even if your DSDT doesn't define
- any ACPI-WMI devices.
-
-config ACPI_ASUS
- tristate "ASUS/Medion Laptop Extras"
- depends on X86
- select BACKLIGHT_CLASS_DEVICE
- ---help---
- This driver provides support for extra features of ACPI-compatible
- ASUS laptops. As some of Medion laptops are made by ASUS, it may also
- support some Medion laptops (such as 9675 for example). It makes all
- the extra buttons generate standard ACPI events that go through
- /proc/acpi/events, and (on some models) adds support for changing the
- display brightness and output, switching the LCD backlight on and off,
- and most importantly, allows you to blink those fancy LEDs intended
- for reporting mail and wireless status.
-
- Note: display switching code is currently considered EXPERIMENTAL,
- toying with these values may even lock your machine.
-
- All settings are changed via /proc/acpi/asus directory entries. Owner
- and group for these entries can be set with asus_uid and asus_gid
- parameters.
-
- More information and a userspace daemon for handling the extra buttons
- at <http://sourceforge.net/projects/acpi4asus/>.
-
- If you have an ACPI-compatible ASUS laptop, say Y or M here. This
- driver is still under development, so if your laptop is unsupported or
- something works not quite as expected, please use the mailing list
- available on the above page (acpi4asus-user@lists.sourceforge.net).
-
- NOTE: This driver is deprecated and will probably be removed soon,
- use asus-laptop instead.
-
-config ACPI_TOSHIBA
- tristate "Toshiba Laptop Extras"
- depends on X86 && INPUT
- select INPUT_POLLDEV
- select NET
- select RFKILL
- select BACKLIGHT_CLASS_DEVICE
- ---help---
- This driver adds support for access to certain system settings
- on "legacy free" Toshiba laptops. These laptops can be recognized by
- their lack of a BIOS setup menu and APM support.
-
- On these machines, all system configuration is handled through the
- ACPI. This driver is required for access to controls not covered
- by the general ACPI drivers, such as LCD brightness, video output,
- etc.
-
- This driver differs from the non-ACPI Toshiba laptop driver (located
- under "Processor type and features") in several aspects.
- Configuration is accessed by reading and writing text files in the
- /proc tree instead of by program interface to /dev. Furthermore, no
- power management functions are exposed, as those are handled by the
- general ACPI drivers.
-
- More information about this driver is available at
- <http://memebeam.org/toys/ToshibaAcpiDriver>.
-
- If you have a legacy free Toshiba laptop (such as the Libretto L1
- series), say Y.
-
config ACPI_CUSTOM_DSDT_FILE
string "Custom DSDT Table file to include"
default ""
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 3c0c93300f12..65d90c720b5a 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -2,15 +2,8 @@
# Makefile for the Linux ACPI interpreter
#
-export ACPI_CFLAGS
-
-ACPI_CFLAGS := -Os
-
-ifdef CONFIG_ACPI_DEBUG
- ACPI_CFLAGS += -DACPI_DEBUG_OUTPUT
-endif
-
-EXTRA_CFLAGS += $(ACPI_CFLAGS)
+ccflags-y := -Os
+ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT
#
# ACPI Boot-Time Table Parsing
@@ -22,9 +15,13 @@ obj-$(CONFIG_X86) += blacklist.o
# ACPI Core Subsystem (Interpreter)
#
obj-y += osl.o utils.o reboot.o\
- dispatcher/ events/ executer/ hardware/ \
- namespace/ parser/ resources/ tables/ \
- utilities/
+ acpica/
+
+# sleep related files
+obj-y += wakeup.o
+obj-y += sleep.o
+obj-$(CONFIG_ACPI_SLEEP) += proc.o
+
#
# ACPI Bus and Device Drivers
@@ -35,7 +32,6 @@ ifdef CONFIG_CPU_FREQ
processor-objs += processor_perflib.o
endif
-obj-y += sleep/
obj-y += bus.o glue.o
obj-y += scan.o
# Keep EC driver first. Initialization of others depend on it.
@@ -59,9 +55,6 @@ obj-y += power.o
obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
obj-$(CONFIG_ACPI_DEBUG) += debug.o
obj-$(CONFIG_ACPI_NUMA) += numa.o
-obj-$(CONFIG_ACPI_WMI) += wmi.o
-obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
-obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
obj-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
obj-$(CONFIG_ACPI_SBS) += sbshc.o
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 63a17b55b39b..7a0f4aa4fa1e 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -20,7 +20,7 @@
*
*
* ACPI based HotPlug driver that supports Memory Hotplug
- * This driver fields notifications from firmare for memory add
+ * This driver fields notifications from firmware for memory add
* and remove operations and alerts the VM of the affected memory
* ranges.
*/
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
new file mode 100644
index 000000000000..3f23298ee3fd
--- /dev/null
+++ b/drivers/acpi/acpica/Makefile
@@ -0,0 +1,44 @@
+#
+# Makefile for ACPICA Core interpreter
+#
+
+ccflags-y := -Os
+ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT
+
+obj-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \
+ dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \
+ dsinit.o
+
+obj-y += evevent.o evregion.o evsci.o evxfevnt.o \
+ evmisc.o evrgnini.o evxface.o evxfregn.o \
+ evgpe.o evgpeblk.o
+
+obj-y += exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\
+ exconvrt.o exfldio.o exoparg1.o exprep.o exresop.o exsystem.o\
+ excreate.o exmisc.o exoparg2.o exregion.o exstore.o exutils.o \
+ exdump.o exmutex.o exoparg3.o exresnte.o exstoren.o
+
+obj-y += hwacpi.o hwgpe.o hwregs.o hwsleep.o hwxface.o
+
+obj-$(ACPI_FUTURE_USAGE) += hwtimer.o
+
+obj-y += nsaccess.o nsload.o nssearch.o nsxfeval.o \
+ nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \
+ nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \
+ nsparse.o nspredef.o
+
+obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o
+
+obj-y += psargs.o psparse.o psloop.o pstree.o pswalk.o \
+ psopcode.o psscope.o psutils.o psxface.o
+
+obj-y += rsaddr.o rscreate.o rsinfo.o rsio.o rslist.o rsmisc.o rsxface.o \
+ rscalc.o rsirq.o rsmemory.o rsutils.o
+
+obj-$(ACPI_FUTURE_USAGE) += rsdump.o
+
+obj-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
+
+obj-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \
+ utcopy.o utdelete.o utglobal.o utmath.o utobject.o \
+ utstate.o utmutex.o utobject.o utresrc.o
diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h
new file mode 100644
index 000000000000..3b20786cbb0d
--- /dev/null
+++ b/drivers/acpi/acpica/accommon.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Name: accommon.h - Common include files for generation of ACPICA source
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACCOMMON_H__
+#define __ACCOMMON_H__
+
+/*
+ * Common set of includes for all ACPICA source files.
+ * We put them here because we don't want to duplicate them
+ * in the the source code again and again.
+ *
+ * Note: The order of these include files is important.
+ */
+#include "acconfig.h" /* Global configuration constants */
+#include "acmacros.h" /* C macros */
+#include "aclocal.h" /* Internal data types */
+#include "acobject.h" /* ACPI internal object */
+#include "acstruct.h" /* Common structures */
+#include "acglobal.h" /* All global variables */
+#include "achware.h" /* Hardware defines and interfaces */
+#include "acutils.h" /* Utility interfaces */
+
+#endif /* __ACCOMMON_H__ */
diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h
new file mode 100644
index 000000000000..e6777fb883d2
--- /dev/null
+++ b/drivers/acpi/acpica/acconfig.h
@@ -0,0 +1,217 @@
+/******************************************************************************
+ *
+ * Name: acconfig.h - Global configuration constants
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 _ACCONFIG_H
+#define _ACCONFIG_H
+
+/******************************************************************************
+ *
+ * Configuration options
+ *
+ *****************************************************************************/
+
+/*
+ * ACPI_DEBUG_OUTPUT - This switch enables all the debug facilities of the
+ * ACPI subsystem. This includes the DEBUG_PRINT output
+ * statements. When disabled, all DEBUG_PRINT
+ * statements are compiled out.
+ *
+ * ACPI_APPLICATION - Use this switch if the subsystem is going to be run
+ * at the application level.
+ *
+ */
+
+/*
+ * OS name, used for the _OS object. The _OS object is essentially obsolete,
+ * but there is a large base of ASL/AML code in existing machines that check
+ * for the string below. The use of this string usually guarantees that
+ * the ASL will execute down the most tested code path. Also, there is some
+ * code that will not execute the _OSI method unless _OS matches the string
+ * below. Therefore, change this string at your own risk.
+ */
+#define ACPI_OS_NAME "Microsoft Windows NT"
+
+/* Maximum objects in the various object caches */
+
+#define ACPI_MAX_STATE_CACHE_DEPTH 96 /* State objects */
+#define ACPI_MAX_PARSE_CACHE_DEPTH 96 /* Parse tree objects */
+#define ACPI_MAX_EXTPARSE_CACHE_DEPTH 96 /* Parse tree objects */
+#define ACPI_MAX_OBJECT_CACHE_DEPTH 96 /* Interpreter operand objects */
+#define ACPI_MAX_NAMESPACE_CACHE_DEPTH 96 /* Namespace objects */
+
+/*
+ * Should the subsystem abort the loading of an ACPI table if the
+ * table checksum is incorrect?
+ */
+#define ACPI_CHECKSUM_ABORT FALSE
+
+/******************************************************************************
+ *
+ * Subsystem Constants
+ *
+ *****************************************************************************/
+
+/* Version of ACPI supported */
+
+#define ACPI_CA_SUPPORT_LEVEL 3
+
+/* Maximum count for a semaphore object */
+
+#define ACPI_MAX_SEMAPHORE_COUNT 256
+
+/* Maximum object reference count (detects object deletion issues) */
+
+#define ACPI_MAX_REFERENCE_COUNT 0x1000
+
+/* Size of cached memory mapping for system memory operation region */
+
+#define ACPI_SYSMEM_REGION_WINDOW_SIZE 4096
+
+/* owner_id tracking. 8 entries allows for 255 owner_ids */
+
+#define ACPI_NUM_OWNERID_MASKS 8
+
+/* Size of the root table array is increased by this increment */
+
+#define ACPI_ROOT_TABLE_SIZE_INCREMENT 4
+
+/* Maximum number of While() loop iterations before forced abort */
+
+#define ACPI_MAX_LOOP_ITERATIONS 0xFFFF
+
+/******************************************************************************
+ *
+ * ACPI Specification constants (Do not change unless the specification changes)
+ *
+ *****************************************************************************/
+
+/* Number of distinct GPE register blocks and register width */
+
+#define ACPI_MAX_GPE_BLOCKS 2
+#define ACPI_GPE_REGISTER_WIDTH 8
+
+/* Method info (in WALK_STATE), containing local variables and argumetns */
+
+#define ACPI_METHOD_NUM_LOCALS 8
+#define ACPI_METHOD_MAX_LOCAL 7
+
+#define ACPI_METHOD_NUM_ARGS 7
+#define ACPI_METHOD_MAX_ARG 6
+
+/* Length of _HID, _UID, _CID, and UUID values */
+
+#define ACPI_DEVICE_ID_LENGTH 0x09
+#define ACPI_MAX_CID_LENGTH 48
+#define ACPI_UUID_LENGTH 16
+
+/*
+ * Operand Stack (in WALK_STATE), Must be large enough to contain METHOD_MAX_ARG
+ */
+#define ACPI_OBJ_NUM_OPERANDS 8
+#define ACPI_OBJ_MAX_OPERAND 7
+
+/* Number of elements in the Result Stack frame, can be an arbitrary value */
+
+#define ACPI_RESULTS_FRAME_OBJ_NUM 8
+
+/*
+ * Maximal number of elements the Result Stack can contain,
+ * it may be an arbitray value not exceeding the types of
+ * result_size and result_count (now u8).
+ */
+#define ACPI_RESULTS_OBJ_NUM_MAX 255
+
+/* Names within the namespace are 4 bytes long */
+
+#define ACPI_NAME_SIZE 4
+#define ACPI_PATH_SEGMENT_LENGTH 5 /* 4 chars for name + 1 char for separator */
+#define ACPI_PATH_SEPARATOR '.'
+
+/* Sizes for ACPI table headers */
+
+#define ACPI_OEM_ID_SIZE 6
+#define ACPI_OEM_TABLE_ID_SIZE 8
+
+/* Constants used in searching for the RSDP in low memory */
+
+#define ACPI_EBDA_PTR_LOCATION 0x0000040E /* Physical Address */
+#define ACPI_EBDA_PTR_LENGTH 2
+#define ACPI_EBDA_WINDOW_SIZE 1024
+#define ACPI_HI_RSDP_WINDOW_BASE 0x000E0000 /* Physical Address */
+#define ACPI_HI_RSDP_WINDOW_SIZE 0x00020000
+#define ACPI_RSDP_SCAN_STEP 16
+
+/* Operation regions */
+
+#define ACPI_NUM_PREDEFINED_REGIONS 8
+#define ACPI_USER_REGION_BEGIN 0x80
+
+/* Maximum space_ids for Operation Regions */
+
+#define ACPI_MAX_ADDRESS_SPACE 255
+
+/* Array sizes. Used for range checking also */
+
+#define ACPI_MAX_MATCH_OPCODE 5
+
+/* RSDP checksums */
+
+#define ACPI_RSDP_CHECKSUM_LENGTH 20
+#define ACPI_RSDP_XCHECKSUM_LENGTH 36
+
+/* SMBus bidirectional buffer size */
+
+#define ACPI_SMBUS_BUFFER_SIZE 34
+
+/******************************************************************************
+ *
+ * ACPI AML Debugger
+ *
+ *****************************************************************************/
+
+#define ACPI_DEBUGGER_MAX_ARGS 8 /* Must be max method args + 1 */
+
+#define ACPI_DEBUGGER_COMMAND_PROMPT '-'
+#define ACPI_DEBUGGER_EXECUTE_PROMPT '%'
+
+#endif /* _ACCONFIG_H */
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
new file mode 100644
index 000000000000..62c59df3b86c
--- /dev/null
+++ b/drivers/acpi/acpica/acdebug.h
@@ -0,0 +1,231 @@
+/******************************************************************************
+ *
+ * Name: acdebug.h - ACPI/AML debugger
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACDEBUG_H__
+#define __ACDEBUG_H__
+
+#define ACPI_DEBUG_BUFFER_SIZE 4196
+
+struct command_info {
+ char *name; /* Command Name */
+ u8 min_args; /* Minimum arguments required */
+};
+
+struct argument_info {
+ char *name; /* Argument Name */
+};
+
+#define PARAM_LIST(pl) pl
+#define DBTEST_OUTPUT_LEVEL(lvl) if (acpi_gbl_db_opt_verbose)
+#define VERBOSE_PRINT(fp) DBTEST_OUTPUT_LEVEL(lvl) {\
+ acpi_os_printf PARAM_LIST(fp);}
+
+#define EX_NO_SINGLE_STEP 1
+#define EX_SINGLE_STEP 2
+
+/*
+ * dbxface - external debugger interfaces
+ */
+acpi_status acpi_db_initialize(void);
+
+void acpi_db_terminate(void);
+
+acpi_status
+acpi_db_single_step(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op, u32 op_type);
+
+/*
+ * dbcmds - debug commands and output routines
+ */
+acpi_status acpi_db_disassemble_method(char *name);
+
+void acpi_db_display_table_info(char *table_arg);
+
+void acpi_db_unload_acpi_table(char *table_arg, char *instance_arg);
+
+void
+acpi_db_set_method_breakpoint(char *location,
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
+void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op);
+
+void acpi_db_get_bus_info(void);
+
+void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op);
+
+void acpi_db_dump_namespace(char *start_arg, char *depth_arg);
+
+void acpi_db_dump_namespace_by_owner(char *owner_arg, char *depth_arg);
+
+void acpi_db_send_notify(char *name, u32 value);
+
+void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg);
+
+acpi_status
+acpi_db_display_objects(char *obj_type_arg, char *display_count_arg);
+
+acpi_status acpi_db_find_name_in_namespace(char *name_arg);
+
+void acpi_db_set_scope(char *name);
+
+acpi_status acpi_db_sleep(char *object_arg);
+
+void acpi_db_find_references(char *object_arg);
+
+void acpi_db_display_locks(void);
+
+void acpi_db_display_resources(char *object_arg);
+
+void acpi_db_display_gpes(void);
+
+void acpi_db_check_integrity(void);
+
+void acpi_db_generate_gpe(char *gpe_arg, char *block_arg);
+
+void acpi_db_check_predefined_names(void);
+
+void acpi_db_batch_execute(void);
+
+/*
+ * dbdisply - debug display commands
+ */
+void acpi_db_display_method_info(union acpi_parse_object *op);
+
+void acpi_db_decode_and_display_object(char *target, char *output_type);
+
+void
+acpi_db_display_result_object(union acpi_operand_object *obj_desc,
+ struct acpi_walk_state *walk_state);
+
+acpi_status acpi_db_display_all_methods(char *display_count_arg);
+
+void acpi_db_display_arguments(void);
+
+void acpi_db_display_locals(void);
+
+void acpi_db_display_results(void);
+
+void acpi_db_display_calling_tree(void);
+
+void acpi_db_display_object_type(char *object_arg);
+
+void
+acpi_db_display_argument_object(union acpi_operand_object *obj_desc,
+ struct acpi_walk_state *walk_state);
+
+void acpi_db_check_predefined_names(void);
+
+void acpi_db_batch_execute(void);
+
+/*
+ * dbexec - debugger control method execution
+ */
+void acpi_db_execute(char *name, char **args, u32 flags);
+
+void
+acpi_db_create_execution_threads(char *num_threads_arg,
+ char *num_loops_arg, char *method_name_arg);
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+u32 acpi_db_get_cache_info(struct acpi_memory_list *cache);
+#endif
+
+/*
+ * dbfileio - Debugger file I/O commands
+ */
+acpi_object_type
+acpi_db_match_argument(char *user_argument, struct argument_info *arguments);
+
+void acpi_db_close_debug_file(void);
+
+void acpi_db_open_debug_file(char *name);
+
+acpi_status acpi_db_load_acpi_table(char *filename);
+
+acpi_status
+acpi_db_get_table_from_file(char *filename, struct acpi_table_header **table);
+
+acpi_status
+acpi_db_read_table_from_file(char *filename, struct acpi_table_header **table);
+
+/*
+ * dbhistry - debugger HISTORY command
+ */
+void acpi_db_add_to_history(char *command_line);
+
+void acpi_db_display_history(void);
+
+char *acpi_db_get_from_history(char *command_num_arg);
+
+/*
+ * dbinput - user front-end to the AML debugger
+ */
+acpi_status
+acpi_db_command_dispatch(char *input_buffer,
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
+void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context);
+
+/*
+ * dbstats - Generation and display of ACPI table statistics
+ */
+void acpi_db_generate_statistics(union acpi_parse_object *root, u8 is_method);
+
+acpi_status acpi_db_display_statistics(char *type_arg);
+
+/*
+ * dbutils - AML debugger utilities
+ */
+void acpi_db_set_output_destination(u32 where);
+
+void acpi_db_dump_external_object(union acpi_object *obj_desc, u32 level);
+
+void acpi_db_prep_namestring(char *name);
+
+struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name);
+
+void acpi_db_uint32_to_hex_string(u32 value, char *buffer);
+
+#endif /* __ACDEBUG_H__ */
diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h
new file mode 100644
index 000000000000..6291904be01e
--- /dev/null
+++ b/drivers/acpi/acpica/acdispat.h
@@ -0,0 +1,345 @@
+/******************************************************************************
+ *
+ * Name: acdispat.h - dispatcher (parser to interpreter interface)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 _ACDISPAT_H_
+#define _ACDISPAT_H_
+
+#define NAMEOF_LOCAL_NTE "__L0"
+#define NAMEOF_ARG_NTE "__A0"
+
+/*
+ * dsopcode - support for late evaluation
+ */
+acpi_status
+acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc);
+
+acpi_status
+acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc);
+
+acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *rgn_desc);
+
+acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc);
+
+acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc);
+
+acpi_status
+acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
+acpi_status
+acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
+acpi_status
+acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
+acpi_status
+acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ union acpi_operand_object *obj_desc);
+
+acpi_status
+acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
+acpi_status acpi_ds_initialize_region(acpi_handle obj_handle);
+
+/*
+ * dsctrl - Parser/Interpreter interface, control stack routines
+ */
+acpi_status
+acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
+acpi_status
+acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
+/*
+ * dsexec - Parser/Interpreter interface, method execution callbacks
+ */
+acpi_status
+acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state,
+ union acpi_operand_object *result_obj);
+
+acpi_status
+acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **out_op);
+
+acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *state);
+
+/*
+ * dsfield - Parser/Interpreter interface for AML fields
+ */
+acpi_status
+acpi_ds_create_field(union acpi_parse_object *op,
+ struct acpi_namespace_node *region_node,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_create_bank_field(union acpi_parse_object *op,
+ struct acpi_namespace_node *region_node,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_create_index_field(union acpi_parse_object *op,
+ struct acpi_namespace_node *region_node,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_create_buffer_field(union acpi_parse_object *op,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_init_field_objects(union acpi_parse_object *op,
+ struct acpi_walk_state *walk_state);
+
+/*
+ * dsload - Parser/Interpreter interface, namespace load callbacks
+ */
+acpi_status
+acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **out_op);
+
+acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **out_op);
+
+acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number);
+
+/*
+ * dsmthdat - method data (locals/args)
+ */
+acpi_status
+acpi_ds_store_object_to_local(u8 type,
+ u32 index,
+ union acpi_operand_object *src_desc,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_method_data_get_entry(u16 opcode,
+ u32 index,
+ struct acpi_walk_state *walk_state,
+ union acpi_operand_object ***node);
+
+void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state);
+
+u8 acpi_ds_is_method_value(union acpi_operand_object *obj_desc);
+
+acpi_status
+acpi_ds_method_data_get_value(u8 type,
+ u32 index,
+ struct acpi_walk_state *walk_state,
+ union acpi_operand_object **dest_desc);
+
+acpi_status
+acpi_ds_method_data_init_args(union acpi_operand_object **params,
+ u32 max_param_count,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_method_data_get_node(u8 type,
+ u32 index,
+ struct acpi_walk_state *walk_state,
+ struct acpi_namespace_node **node);
+
+void acpi_ds_method_data_init(struct acpi_walk_state *walk_state);
+
+/*
+ * dsmethod - Parser/Interpreter interface - control method parsing
+ */
+acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node);
+
+acpi_status
+acpi_ds_call_control_method(struct acpi_thread_state *thread,
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
+acpi_status
+acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
+ union acpi_operand_object *return_desc);
+
+void
+acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
+ union acpi_operand_object *obj_desc,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state);
+
+/*
+ * dsinit
+ */
+acpi_status
+acpi_ds_initialize_objects(u32 table_index,
+ struct acpi_namespace_node *start_node);
+
+/*
+ * dsobject - Parser/Interpreter interface - object initialization and conversion
+ */
+acpi_status
+acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ u32 buffer_length,
+ union acpi_operand_object **obj_desc_ptr);
+
+acpi_status
+acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ u32 package_length,
+ union acpi_operand_object **obj_desc);
+
+acpi_status
+acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ u16 opcode, union acpi_operand_object **obj_desc);
+
+acpi_status
+acpi_ds_create_node(struct acpi_walk_state *walk_state,
+ struct acpi_namespace_node *node,
+ union acpi_parse_object *op);
+
+/*
+ * dsutils - Parser/Interpreter interface utility routines
+ */
+void acpi_ds_clear_implicit_return(struct acpi_walk_state *walk_state);
+
+u8
+acpi_ds_do_implicit_return(union acpi_operand_object *return_desc,
+ struct acpi_walk_state *walk_state,
+ u8 add_reference);
+
+u8
+acpi_ds_is_result_used(union acpi_parse_object *op,
+ struct acpi_walk_state *walk_state);
+
+void
+acpi_ds_delete_result_if_not_used(union acpi_parse_object *op,
+ union acpi_operand_object *result_obj,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_create_operand(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *arg, u32 args_remaining);
+
+acpi_status
+acpi_ds_create_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *first_arg);
+
+acpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state);
+
+void acpi_ds_clear_operands(struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state);
+
+/*
+ * dswscope - Scope Stack manipulation
+ */
+acpi_status
+acpi_ds_scope_stack_push(struct acpi_namespace_node *node,
+ acpi_object_type type,
+ struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ds_scope_stack_pop(struct acpi_walk_state *walk_state);
+
+void acpi_ds_scope_stack_clear(struct acpi_walk_state *walk_state);
+
+/*
+ * dswstate - parser WALK_STATE management routines
+ */
+acpi_status
+acpi_ds_obj_stack_push(void *object, struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state *walk_state);
+
+struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object
+ *origin, union acpi_operand_object
+ *mth_desc, struct acpi_thread_state
+ *thread);
+
+acpi_status
+acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ struct acpi_namespace_node *method_node,
+ u8 * aml_start,
+ u32 aml_length,
+ struct acpi_evaluate_info *info, u8 pass_number);
+
+void
+acpi_ds_obj_stack_pop_and_delete(u32 pop_count,
+ struct acpi_walk_state *walk_state);
+
+void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state);
+
+struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state
+ *thread);
+
+void
+acpi_ds_push_walk_state(struct acpi_walk_state *walk_state,
+ struct acpi_thread_state *thread);
+
+acpi_status acpi_ds_result_stack_clear(struct acpi_walk_state *walk_state);
+
+struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state
+ *thread);
+
+acpi_status
+acpi_ds_result_pop(union acpi_operand_object **object,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_result_push(union acpi_operand_object *object,
+ struct acpi_walk_state *walk_state);
+
+#endif /* _ACDISPAT_H_ */
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
new file mode 100644
index 000000000000..07e20135f01b
--- /dev/null
+++ b/drivers/acpi/acpica/acevents.h
@@ -0,0 +1,218 @@
+/******************************************************************************
+ *
+ * Name: acevents.h - Event subcomponent prototypes and defines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACEVENTS_H__
+#define __ACEVENTS_H__
+
+/*
+ * evevent
+ */
+acpi_status acpi_ev_initialize_events(void);
+
+acpi_status acpi_ev_install_xrupt_handlers(void);
+
+acpi_status acpi_ev_install_fadt_gpes(void);
+
+u32 acpi_ev_fixed_event_detect(void);
+
+/*
+ * evmisc
+ */
+u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node);
+
+acpi_status acpi_ev_acquire_global_lock(u16 timeout);
+
+acpi_status acpi_ev_release_global_lock(void);
+
+acpi_status acpi_ev_init_global_lock_handler(void);
+
+u32 acpi_ev_get_gpe_number_index(u32 gpe_number);
+
+acpi_status
+acpi_ev_queue_notify_request(struct acpi_namespace_node *node,
+ u32 notify_value);
+
+/*
+ * evgpe - GPE handling and dispatch
+ */
+acpi_status
+acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
+ u8 type);
+
+acpi_status
+acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info,
+ u8 write_to_hardware);
+
+acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info);
+
+struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
+ u32 gpe_number);
+
+/*
+ * evgpeblk
+ */
+u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info);
+
+acpi_status
+acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context);
+
+acpi_status
+acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block,
+ void *context);
+
+acpi_status
+acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
+ struct acpi_generic_address *gpe_block_address,
+ u32 register_count,
+ u8 gpe_block_base_number,
+ u32 interrupt_number,
+ struct acpi_gpe_block_info **return_gpe_block);
+
+acpi_status
+acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
+ struct acpi_gpe_block_info *gpe_block);
+
+acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block);
+
+u32
+acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info,
+ u32 gpe_number);
+
+u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list);
+
+acpi_status
+acpi_ev_set_gpe_type(struct acpi_gpe_event_info *gpe_event_info, u8 type);
+
+acpi_status
+acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info);
+
+acpi_status acpi_ev_gpe_initialize(void);
+
+/*
+ * evregion - Address Space handling
+ */
+acpi_status acpi_ev_install_region_handlers(void);
+
+acpi_status acpi_ev_initialize_op_regions(void);
+
+acpi_status
+acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
+ u32 function,
+ acpi_physical_address address,
+ u32 bit_width, acpi_integer * value);
+
+acpi_status
+acpi_ev_attach_region(union acpi_operand_object *handler_obj,
+ union acpi_operand_object *region_obj,
+ u8 acpi_ns_is_locked);
+
+void
+acpi_ev_detach_region(union acpi_operand_object *region_obj,
+ u8 acpi_ns_is_locked);
+
+acpi_status
+acpi_ev_install_space_handler(struct acpi_namespace_node *node,
+ acpi_adr_space_type space_id,
+ acpi_adr_space_handler handler,
+ acpi_adr_space_setup setup, void *context);
+
+acpi_status
+acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
+ acpi_adr_space_type space_id);
+
+acpi_status
+acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function);
+
+/*
+ * evregini - Region initialization and setup
+ */
+acpi_status
+acpi_ev_system_memory_region_setup(acpi_handle handle,
+ u32 function,
+ void *handler_context,
+ void **region_context);
+
+acpi_status
+acpi_ev_io_space_region_setup(acpi_handle handle,
+ u32 function,
+ void *handler_context, void **region_context);
+
+acpi_status
+acpi_ev_pci_config_region_setup(acpi_handle handle,
+ u32 function,
+ void *handler_context, void **region_context);
+
+acpi_status
+acpi_ev_cmos_region_setup(acpi_handle handle,
+ u32 function,
+ void *handler_context, void **region_context);
+
+acpi_status
+acpi_ev_pci_bar_region_setup(acpi_handle handle,
+ u32 function,
+ void *handler_context, void **region_context);
+
+acpi_status
+acpi_ev_default_region_setup(acpi_handle handle,
+ u32 function,
+ void *handler_context, void **region_context);
+
+acpi_status
+acpi_ev_initialize_region(union acpi_operand_object *region_obj,
+ u8 acpi_ns_locked);
+
+/*
+ * evsci - SCI (System Control Interrupt) handling/dispatch
+ */
+u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context);
+
+u32 acpi_ev_install_sci_handler(void);
+
+acpi_status acpi_ev_remove_sci_handler(void);
+
+u32 acpi_ev_initialize_sCI(u32 program_sCI);
+
+void acpi_ev_terminate(void);
+
+#endif /* __ACEVENTS_H__ */
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
new file mode 100644
index 000000000000..ddb40f5c68fc
--- /dev/null
+++ b/drivers/acpi/acpica/acglobal.h
@@ -0,0 +1,394 @@
+/******************************************************************************
+ *
+ * Name: acglobal.h - Declarations for global variables
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACGLOBAL_H__
+#define __ACGLOBAL_H__
+
+/*
+ * Ensure that the globals are actually defined and initialized only once.
+ *
+ * The use of these macros allows a single list of globals (here) in order
+ * to simplify maintenance of the code.
+ */
+#ifdef DEFINE_ACPI_GLOBALS
+#define ACPI_EXTERN
+#define ACPI_INIT_GLOBAL(a,b) a=b
+#else
+#define ACPI_EXTERN extern
+#define ACPI_INIT_GLOBAL(a,b) a
+#endif
+
+/*****************************************************************************
+ *
+ * Runtime configuration (static defaults that can be overriden at runtime)
+ *
+ ****************************************************************************/
+
+/*
+ * Enable "slack" in the AML interpreter? Default is FALSE, and the
+ * interpreter strictly follows the ACPI specification. Setting to TRUE
+ * allows the interpreter to ignore certain errors and/or bad AML constructs.
+ *
+ * Currently, these features are enabled by this flag:
+ *
+ * 1) Allow "implicit return" of last value in a control method
+ * 2) Allow access beyond the end of an operation region
+ * 3) Allow access to uninitialized locals/args (auto-init to integer 0)
+ * 4) Allow ANY object type to be a source operand for the Store() operator
+ * 5) Allow unresolved references (invalid target name) in package objects
+ * 6) Enable warning messages for behavior that is not ACPI spec compliant
+ */
+ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE);
+
+/*
+ * Automatically serialize ALL control methods? Default is FALSE, meaning
+ * to use the Serialized/not_serialized method flags on a per method basis.
+ * Only change this if the ASL code is poorly written and cannot handle
+ * reentrancy even though methods are marked "NotSerialized".
+ */
+ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE);
+
+/*
+ * Create the predefined _OSI method in the namespace? Default is TRUE
+ * because ACPI CA is fully compatible with other ACPI implementations.
+ * Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior.
+ */
+ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE);
+
+/*
+ * Disable wakeup GPEs during runtime? Default is TRUE because WAKE and
+ * RUNTIME GPEs should never be shared, and WAKE GPEs should typically only
+ * be enabled just before going to sleep.
+ */
+ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE);
+
+/*
+ * Optionally use default values for the ACPI register widths. Set this to
+ * TRUE to use the defaults, if an FADT contains incorrect widths/lengths.
+ */
+ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE);
+
+/*****************************************************************************
+ *
+ * Debug support
+ *
+ ****************************************************************************/
+
+/* Runtime configuration of debug print levels */
+
+extern u32 acpi_dbg_level;
+extern u32 acpi_dbg_layer;
+
+/* Procedure nesting level for debug output */
+
+extern u32 acpi_gbl_nesting_level;
+
+/* Support for dynamic control method tracing mechanism */
+
+ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
+ACPI_EXTERN u32 acpi_gbl_original_dbg_layer;
+ACPI_EXTERN acpi_name acpi_gbl_trace_method_name;
+ACPI_EXTERN u32 acpi_gbl_trace_dbg_level;
+ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
+ACPI_EXTERN u32 acpi_gbl_trace_flags;
+
+/*****************************************************************************
+ *
+ * ACPI Table globals
+ *
+ ****************************************************************************/
+
+/*
+ * acpi_gbl_root_table_list is the master list of ACPI tables found in the
+ * RSDT/XSDT.
+ *
+ * acpi_gbl_FADT is a local copy of the FADT, converted to a common format.
+ */
+ACPI_EXTERN struct acpi_internal_rsdt acpi_gbl_root_table_list;
+ACPI_EXTERN struct acpi_table_fadt acpi_gbl_FADT;
+ACPI_EXTERN struct acpi_table_facs *acpi_gbl_FACS;
+
+/* These addresses are calculated from FADT address values */
+
+ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
+ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
+
+/*
+ * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is
+ * determined by the revision of the DSDT: If the DSDT revision is less than
+ * 2, use only the lower 32 bits of the internal 64-bit Integer.
+ */
+ACPI_EXTERN u8 acpi_gbl_integer_bit_width;
+ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
+ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
+
+/*****************************************************************************
+ *
+ * Mutual exlusion within ACPICA subsystem
+ *
+ ****************************************************************************/
+
+/*
+ * Predefined mutex objects. This array contains the
+ * actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs.
+ * (The table maps local handles to the real OS handles)
+ */
+ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[ACPI_NUM_MUTEX];
+
+/*
+ * Global lock mutex is an actual AML mutex object
+ * Global lock semaphore works in conjunction with the HW global lock
+ */
+ACPI_EXTERN union acpi_operand_object *acpi_gbl_global_lock_mutex;
+ACPI_EXTERN acpi_semaphore acpi_gbl_global_lock_semaphore;
+ACPI_EXTERN u16 acpi_gbl_global_lock_handle;
+ACPI_EXTERN u8 acpi_gbl_global_lock_acquired;
+ACPI_EXTERN u8 acpi_gbl_global_lock_present;
+
+/*
+ * Spinlocks are used for interfaces that can be possibly called at
+ * interrupt level
+ */
+ACPI_EXTERN spinlock_t _acpi_gbl_gpe_lock; /* For GPE data structs and registers */
+ACPI_EXTERN spinlock_t _acpi_gbl_hardware_lock; /* For ACPI H/W except GPE registers */
+#define acpi_gbl_gpe_lock &_acpi_gbl_gpe_lock
+#define acpi_gbl_hardware_lock &_acpi_gbl_hardware_lock
+
+/*****************************************************************************
+ *
+ * Miscellaneous globals
+ *
+ ****************************************************************************/
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+
+/* Lists for tracking memory allocations */
+
+ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list;
+ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list;
+ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats;
+#endif
+
+/* Object caches */
+
+ACPI_EXTERN acpi_cache_t *acpi_gbl_namespace_cache;
+ACPI_EXTERN acpi_cache_t *acpi_gbl_state_cache;
+ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_cache;
+ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_ext_cache;
+ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache;
+
+/* Global handlers */
+
+ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_device_notify;
+ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_system_notify;
+ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
+ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
+ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
+ACPI_EXTERN void *acpi_gbl_table_handler_context;
+ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk;
+
+/* Owner ID support */
+
+ACPI_EXTERN u32 acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS];
+ACPI_EXTERN u8 acpi_gbl_last_owner_id_index;
+ACPI_EXTERN u8 acpi_gbl_next_owner_id_offset;
+
+/* Misc */
+
+ACPI_EXTERN u32 acpi_gbl_original_mode;
+ACPI_EXTERN u32 acpi_gbl_rsdp_original_location;
+ACPI_EXTERN u32 acpi_gbl_ns_lookup_count;
+ACPI_EXTERN u32 acpi_gbl_ps_find_count;
+ACPI_EXTERN u16 acpi_gbl_pm1_enable_register_save;
+ACPI_EXTERN u8 acpi_gbl_debugger_configuration;
+ACPI_EXTERN u8 acpi_gbl_step_to_next_call;
+ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present;
+ACPI_EXTERN u8 acpi_gbl_events_initialized;
+ACPI_EXTERN u8 acpi_gbl_system_awake_and_running;
+
+#ifndef DEFINE_ACPI_GLOBALS
+
+/* Other miscellaneous */
+
+extern u8 acpi_gbl_shutdown;
+extern u32 acpi_gbl_startup_flags;
+extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
+extern const char *acpi_gbl_highest_dstate_names[4];
+extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
+extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
+
+#endif
+
+/* Exception codes */
+
+extern char const *acpi_gbl_exception_names_env[];
+extern char const *acpi_gbl_exception_names_pgm[];
+extern char const *acpi_gbl_exception_names_tbl[];
+extern char const *acpi_gbl_exception_names_aml[];
+extern char const *acpi_gbl_exception_names_ctrl[];
+
+/*****************************************************************************
+ *
+ * Namespace globals
+ *
+ ****************************************************************************/
+
+#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
+#define NUM_PREDEFINED_NAMES 10
+#else
+#define NUM_PREDEFINED_NAMES 9
+#endif
+
+ACPI_EXTERN struct acpi_namespace_node acpi_gbl_root_node_struct;
+ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node;
+ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device;
+
+extern const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES];
+extern const struct acpi_predefined_names
+ acpi_gbl_pre_defined_names[NUM_PREDEFINED_NAMES];
+
+#ifdef ACPI_DEBUG_OUTPUT
+ACPI_EXTERN u32 acpi_gbl_current_node_count;
+ACPI_EXTERN u32 acpi_gbl_current_node_size;
+ACPI_EXTERN u32 acpi_gbl_max_concurrent_node_count;
+ACPI_EXTERN acpi_size *acpi_gbl_entry_stack_pointer;
+ACPI_EXTERN acpi_size *acpi_gbl_lowest_stack_pointer;
+ACPI_EXTERN u32 acpi_gbl_deepest_nesting;
+#endif
+
+/*****************************************************************************
+ *
+ * Interpreter globals
+ *
+ ****************************************************************************/
+
+ACPI_EXTERN struct acpi_thread_state *acpi_gbl_current_walk_list;
+
+/* Control method single step flag */
+
+ACPI_EXTERN u8 acpi_gbl_cm_single_step;
+
+/*****************************************************************************
+ *
+ * Hardware globals
+ *
+ ****************************************************************************/
+
+extern struct acpi_bit_register_info
+ acpi_gbl_bit_register_info[ACPI_NUM_BITREG];
+ACPI_EXTERN u8 acpi_gbl_sleep_type_a;
+ACPI_EXTERN u8 acpi_gbl_sleep_type_b;
+
+/*****************************************************************************
+ *
+ * Event and GPE globals
+ *
+ ****************************************************************************/
+
+extern struct acpi_fixed_event_info
+ acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS];
+ACPI_EXTERN struct acpi_fixed_event_handler
+ acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS];
+ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
+ACPI_EXTERN struct acpi_gpe_block_info
+*acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
+ACPI_EXTERN u32 acpi_current_gpe_count;
+
+/*****************************************************************************
+ *
+ * Debugger globals
+ *
+ ****************************************************************************/
+
+ACPI_EXTERN u8 acpi_gbl_db_output_flags;
+
+#ifdef ACPI_DISASSEMBLER
+
+ACPI_EXTERN u8 acpi_gbl_db_opt_disasm;
+ACPI_EXTERN u8 acpi_gbl_db_opt_verbose;
+#endif
+
+#ifdef ACPI_DEBUGGER
+
+extern u8 acpi_gbl_method_executing;
+extern u8 acpi_gbl_abort_method;
+extern u8 acpi_gbl_db_terminate_threads;
+
+ACPI_EXTERN int optind;
+ACPI_EXTERN char *optarg;
+
+ACPI_EXTERN u8 acpi_gbl_db_opt_tables;
+ACPI_EXTERN u8 acpi_gbl_db_opt_stats;
+ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods;
+
+ACPI_EXTERN char *acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS];
+ACPI_EXTERN char acpi_gbl_db_line_buf[80];
+ACPI_EXTERN char acpi_gbl_db_parsed_buf[80];
+ACPI_EXTERN char acpi_gbl_db_scope_buf[40];
+ACPI_EXTERN char acpi_gbl_db_debug_filename[40];
+ACPI_EXTERN u8 acpi_gbl_db_output_to_file;
+ACPI_EXTERN char *acpi_gbl_db_buffer;
+ACPI_EXTERN char *acpi_gbl_db_filename;
+ACPI_EXTERN u32 acpi_gbl_db_debug_level;
+ACPI_EXTERN u32 acpi_gbl_db_console_debug_level;
+ACPI_EXTERN struct acpi_table_header *acpi_gbl_db_table_ptr;
+ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_db_scope_node;
+
+/*
+ * Statistic globals
+ */
+ACPI_EXTERN u16 acpi_gbl_obj_type_count[ACPI_TYPE_NS_NODE_MAX + 1];
+ACPI_EXTERN u16 acpi_gbl_node_type_count[ACPI_TYPE_NS_NODE_MAX + 1];
+ACPI_EXTERN u16 acpi_gbl_obj_type_count_misc;
+ACPI_EXTERN u16 acpi_gbl_node_type_count_misc;
+ACPI_EXTERN u32 acpi_gbl_num_nodes;
+ACPI_EXTERN u32 acpi_gbl_num_objects;
+
+ACPI_EXTERN u32 acpi_gbl_size_of_parse_tree;
+ACPI_EXTERN u32 acpi_gbl_size_of_method_trees;
+ACPI_EXTERN u32 acpi_gbl_size_of_node_entries;
+ACPI_EXTERN u32 acpi_gbl_size_of_acpi_objects;
+
+#endif /* ACPI_DEBUGGER */
+
+#endif /* __ACGLOBAL_H__ */
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
new file mode 100644
index 000000000000..58c69dc49ab4
--- /dev/null
+++ b/drivers/acpi/acpica/achware.h
@@ -0,0 +1,119 @@
+/******************************************************************************
+ *
+ * Name: achware.h -- hardware specific interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACHWARE_H__
+#define __ACHWARE_H__
+
+/* Values for the _SST predefined method */
+
+#define ACPI_SST_INDICATOR_OFF 0
+#define ACPI_SST_WORKING 1
+#define ACPI_SST_WAKING 2
+#define ACPI_SST_SLEEPING 3
+#define ACPI_SST_SLEEP_CONTEXT 4
+
+/*
+ * hwacpi - high level functions
+ */
+acpi_status acpi_hw_set_mode(u32 mode);
+
+u32 acpi_hw_get_mode(void);
+
+/*
+ * hwregs - ACPI Register I/O
+ */
+struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id);
+
+acpi_status
+acpi_hw_register_read(u32 register_id, u32 * return_value);
+
+acpi_status acpi_hw_register_write(u32 register_id, u32 value);
+
+acpi_status acpi_hw_clear_acpi_status(void);
+
+/*
+ * hwgpe - GPE support
+ */
+acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info);
+
+acpi_status
+acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info);
+
+acpi_status
+acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block, void *context);
+
+acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info *gpe_event_info);
+
+acpi_status
+acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block, void *context);
+
+acpi_status
+acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info,
+ acpi_event_status * event_status);
+
+acpi_status acpi_hw_disable_all_gpes(void);
+
+acpi_status acpi_hw_enable_all_runtime_gpes(void);
+
+acpi_status acpi_hw_enable_all_wakeup_gpes(void);
+
+acpi_status
+acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block,
+ void *context);
+
+#ifdef ACPI_FUTURE_USAGE
+/*
+ * hwtimer - ACPI Timer prototypes
+ */
+acpi_status acpi_get_timer_resolution(u32 * resolution);
+
+acpi_status acpi_get_timer(u32 * ticks);
+
+acpi_status
+acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed);
+#endif /* ACPI_FUTURE_USAGE */
+
+#endif /* __ACHWARE_H__ */
diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
new file mode 100644
index 000000000000..e8db7a3143a5
--- /dev/null
+++ b/drivers/acpi/acpica/acinterp.h
@@ -0,0 +1,529 @@
+/******************************************************************************
+ *
+ * Name: acinterp.h - Interpreter subcomponent prototypes and defines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACINTERP_H__
+#define __ACINTERP_H__
+
+#define ACPI_WALK_OPERANDS (&(walk_state->operands [walk_state->num_operands -1]))
+
+/* Macros for tables used for debug output */
+
+#define ACPI_EXD_OFFSET(f) (u8) ACPI_OFFSET (union acpi_operand_object,f)
+#define ACPI_EXD_NSOFFSET(f) (u8) ACPI_OFFSET (struct acpi_namespace_node,f)
+#define ACPI_EXD_TABLE_SIZE(name) (sizeof(name) / sizeof (struct acpi_exdump_info))
+
+/*
+ * If possible, pack the following structures to byte alignment, since we
+ * don't care about performance for debug output. Two cases where we cannot
+ * pack the structures:
+ *
+ * 1) Hardware does not support misaligned memory transfers
+ * 2) Compiler does not support pointers within packed structures
+ */
+#if (!defined(ACPI_MISALIGNMENT_NOT_SUPPORTED) && !defined(ACPI_PACKED_POINTERS_NOT_SUPPORTED))
+#pragma pack(1)
+#endif
+
+typedef const struct acpi_exdump_info {
+ u8 opcode;
+ u8 offset;
+ char *name;
+
+} acpi_exdump_info;
+
+/* Values for the Opcode field above */
+
+#define ACPI_EXD_INIT 0
+#define ACPI_EXD_TYPE 1
+#define ACPI_EXD_UINT8 2
+#define ACPI_EXD_UINT16 3
+#define ACPI_EXD_UINT32 4
+#define ACPI_EXD_UINT64 5
+#define ACPI_EXD_LITERAL 6
+#define ACPI_EXD_POINTER 7
+#define ACPI_EXD_ADDRESS 8
+#define ACPI_EXD_STRING 9
+#define ACPI_EXD_BUFFER 10
+#define ACPI_EXD_PACKAGE 11
+#define ACPI_EXD_FIELD 12
+#define ACPI_EXD_REFERENCE 13
+
+/* restore default alignment */
+
+#pragma pack()
+
+/*
+ * exconvrt - object conversion
+ */
+acpi_status
+acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
+ union acpi_operand_object **result_desc, u32 flags);
+
+acpi_status
+acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
+ union acpi_operand_object **result_desc);
+
+acpi_status
+acpi_ex_convert_to_string(union acpi_operand_object *obj_desc,
+ union acpi_operand_object **result_desc, u32 type);
+
+/* Types for ->String conversion */
+
+#define ACPI_EXPLICIT_BYTE_COPY 0x00000000
+#define ACPI_EXPLICIT_CONVERT_HEX 0x00000001
+#define ACPI_IMPLICIT_CONVERT_HEX 0x00000002
+#define ACPI_EXPLICIT_CONVERT_DECIMAL 0x00000003
+
+acpi_status
+acpi_ex_convert_to_target_type(acpi_object_type destination_type,
+ union acpi_operand_object *source_desc,
+ union acpi_operand_object **result_desc,
+ struct acpi_walk_state *walk_state);
+
+/*
+ * exfield - ACPI AML (p-code) execution - field manipulation
+ */
+acpi_status
+acpi_ex_common_buffer_setup(union acpi_operand_object *obj_desc,
+ u32 buffer_length, u32 * datum_count);
+
+acpi_status
+acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc,
+ acpi_integer mask,
+ acpi_integer field_value,
+ u32 field_datum_byte_offset);
+
+void
+acpi_ex_get_buffer_datum(acpi_integer * datum,
+ void *buffer,
+ u32 buffer_length,
+ u32 byte_granularity, u32 buffer_offset);
+
+void
+acpi_ex_set_buffer_datum(acpi_integer merged_datum,
+ void *buffer,
+ u32 buffer_length,
+ u32 byte_granularity, u32 buffer_offset);
+
+acpi_status
+acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state,
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object **ret_buffer_desc);
+
+acpi_status
+acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object **result_desc);
+
+/*
+ * exfldio - low level field I/O
+ */
+acpi_status
+acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
+ void *buffer, u32 buffer_length);
+
+acpi_status
+acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
+ void *buffer, u32 buffer_length);
+
+acpi_status
+acpi_ex_access_region(union acpi_operand_object *obj_desc,
+ u32 field_datum_byte_offset,
+ acpi_integer * value, u32 read_write);
+
+/*
+ * exmisc - misc support routines
+ */
+acpi_status
+acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
+ union acpi_operand_object **return_desc,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ex_concat_template(union acpi_operand_object *obj_desc,
+ union acpi_operand_object *obj_desc2,
+ union acpi_operand_object **actual_return_desc,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ex_do_concatenate(union acpi_operand_object *obj_desc,
+ union acpi_operand_object *obj_desc2,
+ union acpi_operand_object **actual_return_desc,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ex_do_logical_numeric_op(u16 opcode,
+ acpi_integer integer0,
+ acpi_integer integer1, u8 * logical_result);
+
+acpi_status
+acpi_ex_do_logical_op(u16 opcode,
+ union acpi_operand_object *operand0,
+ union acpi_operand_object *operand1, u8 * logical_result);
+
+acpi_integer
+acpi_ex_do_math_op(u16 opcode, acpi_integer operand0, acpi_integer operand1);
+
+acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ex_create_processor(struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ex_create_power_resource(struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ex_create_region(u8 * aml_start,
+ u32 aml_length,
+ u8 region_space, struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ex_create_method(u8 * aml_start,
+ u32 aml_length, struct acpi_walk_state *walk_state);
+
+/*
+ * exconfig - dynamic table load/unload
+ */
+acpi_status
+acpi_ex_load_op(union acpi_operand_object *obj_desc,
+ union acpi_operand_object *target,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
+ union acpi_operand_object **return_desc);
+
+acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle);
+
+/*
+ * exmutex - mutex support
+ */
+acpi_status
+acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
+ union acpi_operand_object *obj_desc,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ex_acquire_mutex_object(u16 timeout,
+ union acpi_operand_object *obj_desc,
+ acpi_thread_id thread_id);
+
+acpi_status
+acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
+ struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc);
+
+void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread);
+
+void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc);
+
+/*
+ * exprep - ACPI AML execution - prep utilities
+ */
+acpi_status
+acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
+ u8 field_flags,
+ u8 field_attribute,
+ u32 field_bit_position, u32 field_bit_length);
+
+acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info);
+
+/*
+ * exsystem - Interface to OS services
+ */
+acpi_status
+acpi_ex_system_do_notify_op(union acpi_operand_object *value,
+ union acpi_operand_object *obj_desc);
+
+acpi_status acpi_ex_system_do_suspend(acpi_integer time);
+
+acpi_status acpi_ex_system_do_stall(u32 time);
+
+acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc);
+
+acpi_status
+acpi_ex_system_wait_event(union acpi_operand_object *time,
+ union acpi_operand_object *obj_desc);
+
+acpi_status acpi_ex_system_reset_event(union acpi_operand_object *obj_desc);
+
+acpi_status
+acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout);
+
+acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout);
+
+/*
+ * exoparg1 - ACPI AML execution, 1 operand
+ */
+acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ex_opcode_1A_0T_0R(struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ex_opcode_1A_1T_0R(struct acpi_walk_state *walk_state);
+
+/*
+ * exoparg2 - ACPI AML execution, 2 operands
+ */
+acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state);
+
+/*
+ * exoparg3 - ACPI AML execution, 3 operands
+ */
+acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state);
+
+acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state);
+
+/*
+ * exoparg6 - ACPI AML execution, 6 operands
+ */
+acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state *walk_state);
+
+/*
+ * exresolv - Object resolution and get value functions
+ */
+acpi_status
+acpi_ex_resolve_to_value(union acpi_operand_object **stack_ptr,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
+ union acpi_operand_object *operand,
+ acpi_object_type * return_type,
+ union acpi_operand_object **return_desc);
+
+/*
+ * exresnte - resolve namespace node
+ */
+acpi_status
+acpi_ex_resolve_node_to_value(struct acpi_namespace_node **stack_ptr,
+ struct acpi_walk_state *walk_state);
+
+/*
+ * exresop - resolve operand to value
+ */
+acpi_status
+acpi_ex_resolve_operands(u16 opcode,
+ union acpi_operand_object **stack_ptr,
+ struct acpi_walk_state *walk_state);
+
+/*
+ * exdump - Interpreter debug output routines
+ */
+void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth);
+
+void
+acpi_ex_dump_operands(union acpi_operand_object **operands,
+ const char *opcode_name, u32 num_opcodes);
+
+#ifdef ACPI_FUTURE_USAGE
+void
+acpi_ex_dump_object_descriptor(union acpi_operand_object *object, u32 flags);
+
+void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags);
+#endif /* ACPI_FUTURE_USAGE */
+
+/*
+ * exnames - AML namestring support
+ */
+acpi_status
+acpi_ex_get_name_string(acpi_object_type data_type,
+ u8 * in_aml_address,
+ char **out_name_string, u32 * out_name_length);
+
+/*
+ * exstore - Object store support
+ */
+acpi_status
+acpi_ex_store(union acpi_operand_object *val_desc,
+ union acpi_operand_object *dest_desc,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
+ struct acpi_namespace_node *node,
+ struct acpi_walk_state *walk_state,
+ u8 implicit_conversion);
+
+#define ACPI_IMPLICIT_CONVERSION TRUE
+#define ACPI_NO_IMPLICIT_CONVERSION FALSE
+
+/*
+ * exstoren - resolve/store object
+ */
+acpi_status
+acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
+ acpi_object_type target_type,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ex_store_object_to_object(union acpi_operand_object *source_desc,
+ union acpi_operand_object *dest_desc,
+ union acpi_operand_object **new_desc,
+ struct acpi_walk_state *walk_state);
+
+/*
+ * exstorob - store object - buffer/string
+ */
+acpi_status
+acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc,
+ union acpi_operand_object *target_desc);
+
+acpi_status
+acpi_ex_store_string_to_string(union acpi_operand_object *source_desc,
+ union acpi_operand_object *target_desc);
+
+/*
+ * excopy - object copy
+ */
+acpi_status
+acpi_ex_copy_integer_to_index_field(union acpi_operand_object *source_desc,
+ union acpi_operand_object *target_desc);
+
+acpi_status
+acpi_ex_copy_integer_to_bank_field(union acpi_operand_object *source_desc,
+ union acpi_operand_object *target_desc);
+
+acpi_status
+acpi_ex_copy_data_to_named_field(union acpi_operand_object *source_desc,
+ struct acpi_namespace_node *node);
+
+acpi_status
+acpi_ex_copy_integer_to_buffer_field(union acpi_operand_object *source_desc,
+ union acpi_operand_object *target_desc);
+
+/*
+ * exutils - interpreter/scanner utilities
+ */
+void acpi_ex_enter_interpreter(void);
+
+void acpi_ex_exit_interpreter(void);
+
+void acpi_ex_reacquire_interpreter(void);
+
+void acpi_ex_relinquish_interpreter(void);
+
+void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
+
+void acpi_ex_acquire_global_lock(u32 rule);
+
+void acpi_ex_release_global_lock(u32 rule);
+
+void acpi_ex_eisa_id_to_string(u32 numeric_id, char *out_string);
+
+void acpi_ex_unsigned_integer_to_string(acpi_integer value, char *out_string);
+
+/*
+ * exregion - default op_region handlers
+ */
+acpi_status
+acpi_ex_system_memory_space_handler(u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer * value,
+ void *handler_context,
+ void *region_context);
+
+acpi_status
+acpi_ex_system_io_space_handler(u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer * value,
+ void *handler_context, void *region_context);
+
+acpi_status
+acpi_ex_pci_config_space_handler(u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer * value,
+ void *handler_context, void *region_context);
+
+acpi_status
+acpi_ex_cmos_space_handler(u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer * value,
+ void *handler_context, void *region_context);
+
+acpi_status
+acpi_ex_pci_bar_space_handler(u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer * value,
+ void *handler_context, void *region_context);
+
+acpi_status
+acpi_ex_embedded_controller_space_handler(u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer * value,
+ void *handler_context,
+ void *region_context);
+
+acpi_status
+acpi_ex_sm_bus_space_handler(u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer * value,
+ void *handler_context, void *region_context);
+
+acpi_status
+acpi_ex_data_table_space_handler(u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer * value,
+ void *handler_context, void *region_context);
+
+#endif /* __INTERP_H__ */
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
new file mode 100644
index 000000000000..492d02761bb7
--- /dev/null
+++ b/drivers/acpi/acpica/aclocal.h
@@ -0,0 +1,990 @@
+/******************************************************************************
+ *
+ * Name: aclocal.h - Internal data types used across the ACPI subsystem
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACLOCAL_H__
+#define __ACLOCAL_H__
+
+/* acpisrc:struct_defs -- for acpisrc conversion */
+
+#define ACPI_SERIALIZED 0xFF
+
+typedef u32 acpi_mutex_handle;
+#define ACPI_GLOBAL_LOCK (acpi_semaphore) (-1)
+
+/* Total number of aml opcodes defined */
+
+#define AML_NUM_OPCODES 0x7F
+
+/* Forward declarations */
+
+struct acpi_walk_state;
+struct acpi_obj_mutex;
+union acpi_parse_object;
+
+/*****************************************************************************
+ *
+ * Mutex typedefs and structs
+ *
+ ****************************************************************************/
+
+/*
+ * Predefined handles for the mutex objects used within the subsystem
+ * All mutex objects are automatically created by acpi_ut_mutex_initialize.
+ *
+ * The acquire/release ordering protocol is implied via this list. Mutexes
+ * with a lower value must be acquired before mutexes with a higher value.
+ *
+ * NOTE: any changes here must be reflected in the acpi_gbl_mutex_names
+ * table below also!
+ */
+#define ACPI_MTX_INTERPRETER 0 /* AML Interpreter, main lock */
+#define ACPI_MTX_NAMESPACE 1 /* ACPI Namespace */
+#define ACPI_MTX_TABLES 2 /* Data for ACPI tables */
+#define ACPI_MTX_EVENTS 3 /* Data for ACPI events */
+#define ACPI_MTX_CACHES 4 /* Internal caches, general purposes */
+#define ACPI_MTX_MEMORY 5 /* Debug memory tracking lists */
+#define ACPI_MTX_DEBUG_CMD_COMPLETE 6 /* AML debugger */
+#define ACPI_MTX_DEBUG_CMD_READY 7 /* AML debugger */
+
+#define ACPI_MAX_MUTEX 7
+#define ACPI_NUM_MUTEX ACPI_MAX_MUTEX+1
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+#ifdef DEFINE_ACPI_GLOBALS
+
+/* Debug names for the mutexes above */
+
+static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = {
+ "ACPI_MTX_Interpreter",
+ "ACPI_MTX_Namespace",
+ "ACPI_MTX_Tables",
+ "ACPI_MTX_Events",
+ "ACPI_MTX_Caches",
+ "ACPI_MTX_Memory",
+ "ACPI_MTX_CommandComplete",
+ "ACPI_MTX_CommandReady"
+};
+
+#endif
+#endif
+
+/*
+ * Predefined handles for spinlocks used within the subsystem.
+ * These spinlocks are created by acpi_ut_mutex_initialize
+ */
+#define ACPI_LOCK_GPES 0
+#define ACPI_LOCK_HARDWARE 1
+
+#define ACPI_MAX_LOCK 1
+#define ACPI_NUM_LOCK ACPI_MAX_LOCK+1
+
+/* This Thread ID means that the mutex is not in use (unlocked) */
+
+#define ACPI_MUTEX_NOT_ACQUIRED (acpi_thread_id) 0
+
+/* Table for the global mutexes */
+
+struct acpi_mutex_info {
+ acpi_mutex mutex;
+ u32 use_count;
+ acpi_thread_id thread_id;
+};
+
+/* Lock flag parameter for various interfaces */
+
+#define ACPI_MTX_DO_NOT_LOCK 0
+#define ACPI_MTX_LOCK 1
+
+/* Field access granularities */
+
+#define ACPI_FIELD_BYTE_GRANULARITY 1
+#define ACPI_FIELD_WORD_GRANULARITY 2
+#define ACPI_FIELD_DWORD_GRANULARITY 4
+#define ACPI_FIELD_QWORD_GRANULARITY 8
+
+#define ACPI_ENTRY_NOT_FOUND NULL
+
+/*****************************************************************************
+ *
+ * Namespace typedefs and structs
+ *
+ ****************************************************************************/
+
+/* Operational modes of the AML interpreter/scanner */
+
+typedef enum {
+ ACPI_IMODE_LOAD_PASS1 = 0x01,
+ ACPI_IMODE_LOAD_PASS2 = 0x02,
+ ACPI_IMODE_EXECUTE = 0x03
+} acpi_interpreter_mode;
+
+/*
+ * The Namespace Node describes a named object that appears in the AML.
+ * descriptor_type is used to differentiate between internal descriptors.
+ *
+ * The node is optimized for both 32-bit and 64-bit platforms:
+ * 20 bytes for the 32-bit case, 32 bytes for the 64-bit case.
+ *
+ * Note: The descriptor_type and Type fields must appear in the identical
+ * position in both the struct acpi_namespace_node and union acpi_operand_object
+ * structures.
+ */
+struct acpi_namespace_node {
+ union acpi_operand_object *object; /* Interpreter object */
+ u8 descriptor_type; /* Differentiate object descriptor types */
+ u8 type; /* ACPI Type associated with this name */
+ u8 flags; /* Miscellaneous flags */
+ acpi_owner_id owner_id; /* Node creator */
+ union acpi_name_union name; /* ACPI Name, always 4 chars per ACPI spec */
+ struct acpi_namespace_node *child; /* First child */
+ struct acpi_namespace_node *peer; /* Peer. Parent if ANOBJ_END_OF_PEER_LIST set */
+
+ /*
+ * The following fields are used by the ASL compiler and disassembler only
+ */
+#ifdef ACPI_LARGE_NAMESPACE_NODE
+ union acpi_parse_object *op;
+ u32 value;
+ u32 length;
+#endif
+};
+
+/* Namespace Node flags */
+
+#define ANOBJ_END_OF_PEER_LIST 0x01 /* End-of-list, Peer field points to parent */
+#define ANOBJ_TEMPORARY 0x02 /* Node is create by a method and is temporary */
+#define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */
+#define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */
+#define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */
+#define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */
+
+#define ANOBJ_IS_EXTERNAL 0x08 /* i_aSL only: This object created via External() */
+#define ANOBJ_METHOD_NO_RETVAL 0x10 /* i_aSL only: Method has no return value */
+#define ANOBJ_METHOD_SOME_NO_RETVAL 0x20 /* i_aSL only: Method has at least one return value */
+#define ANOBJ_IS_BIT_OFFSET 0x40 /* i_aSL only: Reference is a bit offset */
+#define ANOBJ_IS_REFERENCED 0x80 /* i_aSL only: Object was referenced */
+
+/* One internal RSDT for table management */
+
+struct acpi_internal_rsdt {
+ struct acpi_table_desc *tables;
+ u32 count;
+ u32 size;
+ u8 flags;
+};
+
+/* Flags for above */
+
+#define ACPI_ROOT_ORIGIN_UNKNOWN (0) /* ~ORIGIN_ALLOCATED */
+#define ACPI_ROOT_ORIGIN_ALLOCATED (1)
+#define ACPI_ROOT_ALLOW_RESIZE (2)
+
+/* Predefined (fixed) table indexes */
+
+#define ACPI_TABLE_INDEX_DSDT (0)
+#define ACPI_TABLE_INDEX_FACS (1)
+
+struct acpi_find_context {
+ char *search_for;
+ acpi_handle *list;
+ u32 *count;
+};
+
+struct acpi_ns_search_data {
+ struct acpi_namespace_node *node;
+};
+
+/* Object types used during package copies */
+
+#define ACPI_COPY_TYPE_SIMPLE 0
+#define ACPI_COPY_TYPE_PACKAGE 1
+
+/* Info structure used to convert external<->internal namestrings */
+
+struct acpi_namestring_info {
+ const char *external_name;
+ const char *next_external_char;
+ char *internal_name;
+ u32 length;
+ u32 num_segments;
+ u32 num_carats;
+ u8 fully_qualified;
+};
+
+/* Field creation info */
+
+struct acpi_create_field_info {
+ struct acpi_namespace_node *region_node;
+ struct acpi_namespace_node *field_node;
+ struct acpi_namespace_node *register_node;
+ struct acpi_namespace_node *data_register_node;
+ u32 bank_value;
+ u32 field_bit_position;
+ u32 field_bit_length;
+ u8 field_flags;
+ u8 attribute;
+ u8 field_type;
+};
+
+typedef
+acpi_status(*ACPI_INTERNAL_METHOD) (struct acpi_walk_state * walk_state);
+
+/*
+ * Bitmapped ACPI types. Used internally only
+ */
+#define ACPI_BTYPE_ANY 0x00000000
+#define ACPI_BTYPE_INTEGER 0x00000001
+#define ACPI_BTYPE_STRING 0x00000002
+#define ACPI_BTYPE_BUFFER 0x00000004
+#define ACPI_BTYPE_PACKAGE 0x00000008
+#define ACPI_BTYPE_FIELD_UNIT 0x00000010
+#define ACPI_BTYPE_DEVICE 0x00000020
+#define ACPI_BTYPE_EVENT 0x00000040
+#define ACPI_BTYPE_METHOD 0x00000080
+#define ACPI_BTYPE_MUTEX 0x00000100
+#define ACPI_BTYPE_REGION 0x00000200
+#define ACPI_BTYPE_POWER 0x00000400
+#define ACPI_BTYPE_PROCESSOR 0x00000800
+#define ACPI_BTYPE_THERMAL 0x00001000
+#define ACPI_BTYPE_BUFFER_FIELD 0x00002000
+#define ACPI_BTYPE_DDB_HANDLE 0x00004000
+#define ACPI_BTYPE_DEBUG_OBJECT 0x00008000
+#define ACPI_BTYPE_REFERENCE 0x00010000
+#define ACPI_BTYPE_RESOURCE 0x00020000
+
+#define ACPI_BTYPE_COMPUTE_DATA (ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER)
+
+#define ACPI_BTYPE_DATA (ACPI_BTYPE_COMPUTE_DATA | ACPI_BTYPE_PACKAGE)
+#define ACPI_BTYPE_DATA_REFERENCE (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE | ACPI_BTYPE_DDB_HANDLE)
+#define ACPI_BTYPE_DEVICE_OBJECTS (ACPI_BTYPE_DEVICE | ACPI_BTYPE_THERMAL | ACPI_BTYPE_PROCESSOR)
+#define ACPI_BTYPE_OBJECTS_AND_REFS 0x0001FFFF /* ARG or LOCAL */
+#define ACPI_BTYPE_ALL_OBJECTS 0x0000FFFF
+
+/*
+ * Information structure for ACPI predefined names.
+ * Each entry in the table contains the following items:
+ *
+ * Name - The ACPI reserved name
+ * param_count - Number of arguments to the method
+ * expected_return_btypes - Allowed type(s) for the return value
+ */
+struct acpi_name_info {
+ char name[ACPI_NAME_SIZE];
+ u8 param_count;
+ u8 expected_btypes;
+};
+
+/*
+ * Secondary information structures for ACPI predefined objects that return
+ * package objects. This structure appears as the next entry in the table
+ * after the NAME_INFO structure above.
+ *
+ * The reason for this is to minimize the size of the predefined name table.
+ */
+
+/*
+ * Used for ACPI_PTYPE1_FIXED, ACPI_PTYPE1_VAR, ACPI_PTYPE2,
+ * ACPI_PTYPE2_MIN, ACPI_PTYPE2_PKG_COUNT, ACPI_PTYPE2_COUNT
+ */
+struct acpi_package_info {
+ u8 type;
+ u8 object_type1;
+ u8 count1;
+ u8 object_type2;
+ u8 count2;
+ u8 reserved;
+};
+
+/* Used for ACPI_PTYPE2_FIXED */
+
+struct acpi_package_info2 {
+ u8 type;
+ u8 count;
+ u8 object_type[4];
+};
+
+/* Used for ACPI_PTYPE1_OPTION */
+
+struct acpi_package_info3 {
+ u8 type;
+ u8 count;
+ u8 object_type[2];
+ u8 tail_object_type;
+ u8 reserved;
+};
+
+union acpi_predefined_info {
+ struct acpi_name_info info;
+ struct acpi_package_info ret_info;
+ struct acpi_package_info2 ret_info2;
+ struct acpi_package_info3 ret_info3;
+};
+
+/*
+ * Bitmapped return value types
+ * Note: the actual data types must be contiguous, a loop in nspredef.c
+ * depends on this.
+ */
+#define ACPI_RTYPE_ANY 0x00
+#define ACPI_RTYPE_NONE 0x01
+#define ACPI_RTYPE_INTEGER 0x02
+#define ACPI_RTYPE_STRING 0x04
+#define ACPI_RTYPE_BUFFER 0x08
+#define ACPI_RTYPE_PACKAGE 0x10
+#define ACPI_RTYPE_REFERENCE 0x20
+#define ACPI_RTYPE_ALL 0x3F
+
+#define ACPI_NUM_RTYPES 5 /* Number of actual object types */
+
+/*****************************************************************************
+ *
+ * Event typedefs and structs
+ *
+ ****************************************************************************/
+
+/* Dispatch info for each GPE -- either a method or handler, cannot be both */
+
+struct acpi_handler_info {
+ acpi_event_handler address; /* Address of handler, if any */
+ void *context; /* Context to be passed to handler */
+ struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */
+};
+
+union acpi_gpe_dispatch_info {
+ struct acpi_namespace_node *method_node; /* Method node for this GPE level */
+ struct acpi_handler_info *handler;
+};
+
+/*
+ * Information about a GPE, one per each GPE in an array.
+ * NOTE: Important to keep this struct as small as possible.
+ */
+struct acpi_gpe_event_info {
+ union acpi_gpe_dispatch_info dispatch; /* Either Method or Handler */
+ struct acpi_gpe_register_info *register_info; /* Backpointer to register info */
+ u8 flags; /* Misc info about this GPE */
+ u8 gpe_number; /* This GPE */
+};
+
+/* Information about a GPE register pair, one per each status/enable pair in an array */
+
+struct acpi_gpe_register_info {
+ struct acpi_generic_address status_address; /* Address of status reg */
+ struct acpi_generic_address enable_address; /* Address of enable reg */
+ u8 enable_for_wake; /* GPEs to keep enabled when sleeping */
+ u8 enable_for_run; /* GPEs to keep enabled when running */
+ u8 base_gpe_number; /* Base GPE number for this register */
+};
+
+/*
+ * Information about a GPE register block, one per each installed block --
+ * GPE0, GPE1, and one per each installed GPE Block Device.
+ */
+struct acpi_gpe_block_info {
+ struct acpi_namespace_node *node;
+ struct acpi_gpe_block_info *previous;
+ struct acpi_gpe_block_info *next;
+ struct acpi_gpe_xrupt_info *xrupt_block; /* Backpointer to interrupt block */
+ struct acpi_gpe_register_info *register_info; /* One per GPE register pair */
+ struct acpi_gpe_event_info *event_info; /* One for each GPE */
+ struct acpi_generic_address block_address; /* Base address of the block */
+ u32 register_count; /* Number of register pairs in block */
+ u8 block_base_number; /* Base GPE number for this block */
+};
+
+/* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */
+
+struct acpi_gpe_xrupt_info {
+ struct acpi_gpe_xrupt_info *previous;
+ struct acpi_gpe_xrupt_info *next;
+ struct acpi_gpe_block_info *gpe_block_list_head; /* List of GPE blocks for this xrupt */
+ u32 interrupt_number; /* System interrupt number */
+};
+
+struct acpi_gpe_walk_info {
+ struct acpi_namespace_node *gpe_device;
+ struct acpi_gpe_block_info *gpe_block;
+};
+
+struct acpi_gpe_device_info {
+ u32 index;
+ u32 next_block_base_index;
+ acpi_status status;
+ struct acpi_namespace_node *gpe_device;
+};
+
+typedef acpi_status(*acpi_gpe_callback) (struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block, void *context);
+
+/* Information about each particular fixed event */
+
+struct acpi_fixed_event_handler {
+ acpi_event_handler handler; /* Address of handler. */
+ void *context; /* Context to be passed to handler */
+};
+
+struct acpi_fixed_event_info {
+ u8 status_register_id;
+ u8 enable_register_id;
+ u16 status_bit_mask;
+ u16 enable_bit_mask;
+};
+
+/* Information used during field processing */
+
+struct acpi_field_info {
+ u8 skip_field;
+ u8 field_flag;
+ u32 pkg_length;
+};
+
+/*****************************************************************************
+ *
+ * Generic "state" object for stacks
+ *
+ ****************************************************************************/
+
+#define ACPI_CONTROL_NORMAL 0xC0
+#define ACPI_CONTROL_CONDITIONAL_EXECUTING 0xC1
+#define ACPI_CONTROL_PREDICATE_EXECUTING 0xC2
+#define ACPI_CONTROL_PREDICATE_FALSE 0xC3
+#define ACPI_CONTROL_PREDICATE_TRUE 0xC4
+
+#define ACPI_STATE_COMMON \
+ void *next; \
+ u8 descriptor_type; /* To differentiate various internal objs */\
+ u8 flags; \
+ u16 value; \
+ u16 state;
+
+ /* There are 2 bytes available here until the next natural alignment boundary */
+
+struct acpi_common_state {
+ACPI_STATE_COMMON};
+
+/*
+ * Update state - used to traverse complex objects such as packages
+ */
+struct acpi_update_state {
+ ACPI_STATE_COMMON union acpi_operand_object *object;
+};
+
+/*
+ * Pkg state - used to traverse nested package structures
+ */
+struct acpi_pkg_state {
+ ACPI_STATE_COMMON u16 index;
+ union acpi_operand_object *source_object;
+ union acpi_operand_object *dest_object;
+ struct acpi_walk_state *walk_state;
+ void *this_target_obj;
+ u32 num_packages;
+};
+
+/*
+ * Control state - one per if/else and while constructs.
+ * Allows nesting of these constructs
+ */
+struct acpi_control_state {
+ ACPI_STATE_COMMON u16 opcode;
+ union acpi_parse_object *predicate_op;
+ u8 *aml_predicate_start; /* Start of if/while predicate */
+ u8 *package_end; /* End of if/while block */
+ u32 loop_count; /* While() loop counter */
+};
+
+/*
+ * Scope state - current scope during namespace lookups
+ */
+struct acpi_scope_state {
+ ACPI_STATE_COMMON struct acpi_namespace_node *node;
+};
+
+struct acpi_pscope_state {
+ ACPI_STATE_COMMON u32 arg_count; /* Number of fixed arguments */
+ union acpi_parse_object *op; /* Current op being parsed */
+ u8 *arg_end; /* Current argument end */
+ u8 *pkg_end; /* Current package end */
+ u32 arg_list; /* Next argument to parse */
+};
+
+/*
+ * Thread state - one per thread across multiple walk states. Multiple walk
+ * states are created when there are nested control methods executing.
+ */
+struct acpi_thread_state {
+ ACPI_STATE_COMMON u8 current_sync_level; /* Mutex Sync (nested acquire) level */
+ struct acpi_walk_state *walk_state_list; /* Head of list of walk_states for this thread */
+ union acpi_operand_object *acquired_mutex_list; /* List of all currently acquired mutexes */
+ acpi_thread_id thread_id; /* Running thread ID */
+};
+
+/*
+ * Result values - used to accumulate the results of nested
+ * AML arguments
+ */
+struct acpi_result_values {
+ ACPI_STATE_COMMON
+ union acpi_operand_object *obj_desc[ACPI_RESULTS_FRAME_OBJ_NUM];
+};
+
+typedef
+acpi_status(*acpi_parse_downwards) (struct acpi_walk_state * walk_state,
+ union acpi_parse_object ** out_op);
+
+typedef acpi_status(*acpi_parse_upwards) (struct acpi_walk_state * walk_state);
+
+/*
+ * Notify info - used to pass info to the deferred notify
+ * handler/dispatcher.
+ */
+struct acpi_notify_info {
+ ACPI_STATE_COMMON struct acpi_namespace_node *node;
+ union acpi_operand_object *handler_obj;
+};
+
+/* Generic state is union of structs above */
+
+union acpi_generic_state {
+ struct acpi_common_state common;
+ struct acpi_control_state control;
+ struct acpi_update_state update;
+ struct acpi_scope_state scope;
+ struct acpi_pscope_state parse_scope;
+ struct acpi_pkg_state pkg;
+ struct acpi_thread_state thread;
+ struct acpi_result_values results;
+ struct acpi_notify_info notify;
+};
+
+/*****************************************************************************
+ *
+ * Interpreter typedefs and structs
+ *
+ ****************************************************************************/
+
+typedef acpi_status(*ACPI_EXECUTE_OP) (struct acpi_walk_state * walk_state);
+
+/*****************************************************************************
+ *
+ * Parser typedefs and structs
+ *
+ ****************************************************************************/
+
+/*
+ * AML opcode, name, and argument layout
+ */
+struct acpi_opcode_info {
+#if defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUG_OUTPUT)
+ char *name; /* Opcode name (disassembler/debug only) */
+#endif
+ u32 parse_args; /* Grammar/Parse time arguments */
+ u32 runtime_args; /* Interpret time arguments */
+ u16 flags; /* Misc flags */
+ u8 object_type; /* Corresponding internal object type */
+ u8 class; /* Opcode class */
+ u8 type; /* Opcode type */
+};
+
+union acpi_parse_value {
+ acpi_integer integer; /* Integer constant (Up to 64 bits) */
+ struct uint64_struct integer64; /* Structure overlay for 2 32-bit Dwords */
+ u32 size; /* bytelist or field size */
+ char *string; /* NULL terminated string */
+ u8 *buffer; /* buffer or string */
+ char *name; /* NULL terminated string */
+ union acpi_parse_object *arg; /* arguments and contained ops */
+};
+
+#ifdef ACPI_DISASSEMBLER
+#define ACPI_DISASM_ONLY_MEMBERS(a) a;
+#else
+#define ACPI_DISASM_ONLY_MEMBERS(a)
+#endif
+
+#define ACPI_PARSE_COMMON \
+ union acpi_parse_object *parent; /* Parent op */\
+ u8 descriptor_type; /* To differentiate various internal objs */\
+ u8 flags; /* Type of Op */\
+ u16 aml_opcode; /* AML opcode */\
+ u32 aml_offset; /* Offset of declaration in AML */\
+ union acpi_parse_object *next; /* Next op */\
+ struct acpi_namespace_node *node; /* For use by interpreter */\
+ union acpi_parse_value value; /* Value or args associated with the opcode */\
+ u8 arg_list_length; /* Number of elements in the arg list */\
+ ACPI_DISASM_ONLY_MEMBERS (\
+ u8 disasm_flags; /* Used during AML disassembly */\
+ u8 disasm_opcode; /* Subtype used for disassembly */\
+ char aml_op_name[16]) /* Op name (debug only) */
+
+#define ACPI_DASM_BUFFER 0x00
+#define ACPI_DASM_RESOURCE 0x01
+#define ACPI_DASM_STRING 0x02
+#define ACPI_DASM_UNICODE 0x03
+#define ACPI_DASM_EISAID 0x04
+#define ACPI_DASM_MATCHOP 0x05
+#define ACPI_DASM_LNOT_PREFIX 0x06
+#define ACPI_DASM_LNOT_SUFFIX 0x07
+#define ACPI_DASM_IGNORE 0x08
+
+/*
+ * Generic operation (for example: If, While, Store)
+ */
+struct acpi_parse_obj_common {
+ACPI_PARSE_COMMON};
+
+/*
+ * Extended Op for named ops (Scope, Method, etc.), deferred ops (Methods and op_regions),
+ * and bytelists.
+ */
+struct acpi_parse_obj_named {
+ ACPI_PARSE_COMMON u8 *path;
+ u8 *data; /* AML body or bytelist data */
+ u32 length; /* AML length */
+ u32 name; /* 4-byte name or zero if no name */
+};
+
+/* This version is used by the i_aSL compiler only */
+
+#define ACPI_MAX_PARSEOP_NAME 20
+
+struct acpi_parse_obj_asl {
+ ACPI_PARSE_COMMON union acpi_parse_object *child;
+ union acpi_parse_object *parent_method;
+ char *filename;
+ char *external_name;
+ char *namepath;
+ char name_seg[4];
+ u32 extra_value;
+ u32 column;
+ u32 line_number;
+ u32 logical_line_number;
+ u32 logical_byte_offset;
+ u32 end_line;
+ u32 end_logical_line;
+ u32 acpi_btype;
+ u32 aml_length;
+ u32 aml_subtree_length;
+ u32 final_aml_length;
+ u32 final_aml_offset;
+ u32 compile_flags;
+ u16 parse_opcode;
+ u8 aml_opcode_length;
+ u8 aml_pkg_len_bytes;
+ u8 extra;
+ char parse_op_name[ACPI_MAX_PARSEOP_NAME];
+};
+
+union acpi_parse_object {
+ struct acpi_parse_obj_common common;
+ struct acpi_parse_obj_named named;
+ struct acpi_parse_obj_asl asl;
+};
+
+/*
+ * Parse state - one state per parser invocation and each control
+ * method.
+ */
+struct acpi_parse_state {
+ u8 *aml_start; /* First AML byte */
+ u8 *aml; /* Next AML byte */
+ u8 *aml_end; /* (last + 1) AML byte */
+ u8 *pkg_start; /* Current package begin */
+ u8 *pkg_end; /* Current package end */
+ union acpi_parse_object *start_op; /* Root of parse tree */
+ struct acpi_namespace_node *start_node;
+ union acpi_generic_state *scope; /* Current scope */
+ union acpi_parse_object *start_scope;
+ u32 aml_size;
+};
+
+/* Parse object flags */
+
+#define ACPI_PARSEOP_GENERIC 0x01
+#define ACPI_PARSEOP_NAMED 0x02
+#define ACPI_PARSEOP_DEFERRED 0x04
+#define ACPI_PARSEOP_BYTELIST 0x08
+#define ACPI_PARSEOP_IN_STACK 0x10
+#define ACPI_PARSEOP_TARGET 0x20
+#define ACPI_PARSEOP_IN_CACHE 0x80
+
+/* Parse object disasm_flags */
+
+#define ACPI_PARSEOP_IGNORE 0x01
+#define ACPI_PARSEOP_PARAMLIST 0x02
+#define ACPI_PARSEOP_EMPTY_TERMLIST 0x04
+#define ACPI_PARSEOP_SPECIAL 0x10
+
+/*****************************************************************************
+ *
+ * Hardware (ACPI registers) and PNP
+ *
+ ****************************************************************************/
+
+struct acpi_bit_register_info {
+ u8 parent_register;
+ u8 bit_position;
+ u16 access_bit_mask;
+};
+
+/*
+ * Some ACPI registers have bits that must be ignored -- meaning that they
+ * must be preserved.
+ */
+#define ACPI_PM1_STATUS_PRESERVED_BITS 0x0800 /* Bit 11 */
+#define ACPI_PM1_CONTROL_PRESERVED_BITS 0x0200 /* Bit 9 (whatever) */
+
+/*
+ * Register IDs
+ * These are the full ACPI registers
+ */
+#define ACPI_REGISTER_PM1_STATUS 0x01
+#define ACPI_REGISTER_PM1_ENABLE 0x02
+#define ACPI_REGISTER_PM1_CONTROL 0x03
+#define ACPI_REGISTER_PM1A_CONTROL 0x04
+#define ACPI_REGISTER_PM1B_CONTROL 0x05
+#define ACPI_REGISTER_PM2_CONTROL 0x06
+#define ACPI_REGISTER_PM_TIMER 0x07
+#define ACPI_REGISTER_PROCESSOR_BLOCK 0x08
+#define ACPI_REGISTER_SMI_COMMAND_BLOCK 0x09
+
+/* Masks used to access the bit_registers */
+
+#define ACPI_BITMASK_TIMER_STATUS 0x0001
+#define ACPI_BITMASK_BUS_MASTER_STATUS 0x0010
+#define ACPI_BITMASK_GLOBAL_LOCK_STATUS 0x0020
+#define ACPI_BITMASK_POWER_BUTTON_STATUS 0x0100
+#define ACPI_BITMASK_SLEEP_BUTTON_STATUS 0x0200
+#define ACPI_BITMASK_RT_CLOCK_STATUS 0x0400
+#define ACPI_BITMASK_PCIEXP_WAKE_STATUS 0x4000 /* ACPI 3.0 */
+#define ACPI_BITMASK_WAKE_STATUS 0x8000
+
+#define ACPI_BITMASK_ALL_FIXED_STATUS (\
+ ACPI_BITMASK_TIMER_STATUS | \
+ ACPI_BITMASK_BUS_MASTER_STATUS | \
+ ACPI_BITMASK_GLOBAL_LOCK_STATUS | \
+ ACPI_BITMASK_POWER_BUTTON_STATUS | \
+ ACPI_BITMASK_SLEEP_BUTTON_STATUS | \
+ ACPI_BITMASK_RT_CLOCK_STATUS | \
+ ACPI_BITMASK_WAKE_STATUS)
+
+#define ACPI_BITMASK_TIMER_ENABLE 0x0001
+#define ACPI_BITMASK_GLOBAL_LOCK_ENABLE 0x0020
+#define ACPI_BITMASK_POWER_BUTTON_ENABLE 0x0100
+#define ACPI_BITMASK_SLEEP_BUTTON_ENABLE 0x0200
+#define ACPI_BITMASK_RT_CLOCK_ENABLE 0x0400
+#define ACPI_BITMASK_PCIEXP_WAKE_DISABLE 0x4000 /* ACPI 3.0 */
+
+#define ACPI_BITMASK_SCI_ENABLE 0x0001
+#define ACPI_BITMASK_BUS_MASTER_RLD 0x0002
+#define ACPI_BITMASK_GLOBAL_LOCK_RELEASE 0x0004
+#define ACPI_BITMASK_SLEEP_TYPE_X 0x1C00
+#define ACPI_BITMASK_SLEEP_ENABLE 0x2000
+
+#define ACPI_BITMASK_ARB_DISABLE 0x0001
+
+/* Raw bit position of each bit_register */
+
+#define ACPI_BITPOSITION_TIMER_STATUS 0x00
+#define ACPI_BITPOSITION_BUS_MASTER_STATUS 0x04
+#define ACPI_BITPOSITION_GLOBAL_LOCK_STATUS 0x05
+#define ACPI_BITPOSITION_POWER_BUTTON_STATUS 0x08
+#define ACPI_BITPOSITION_SLEEP_BUTTON_STATUS 0x09
+#define ACPI_BITPOSITION_RT_CLOCK_STATUS 0x0A
+#define ACPI_BITPOSITION_PCIEXP_WAKE_STATUS 0x0E /* ACPI 3.0 */
+#define ACPI_BITPOSITION_WAKE_STATUS 0x0F
+
+#define ACPI_BITPOSITION_TIMER_ENABLE 0x00
+#define ACPI_BITPOSITION_GLOBAL_LOCK_ENABLE 0x05
+#define ACPI_BITPOSITION_POWER_BUTTON_ENABLE 0x08
+#define ACPI_BITPOSITION_SLEEP_BUTTON_ENABLE 0x09
+#define ACPI_BITPOSITION_RT_CLOCK_ENABLE 0x0A
+#define ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE 0x0E /* ACPI 3.0 */
+
+#define ACPI_BITPOSITION_SCI_ENABLE 0x00
+#define ACPI_BITPOSITION_BUS_MASTER_RLD 0x01
+#define ACPI_BITPOSITION_GLOBAL_LOCK_RELEASE 0x02
+#define ACPI_BITPOSITION_SLEEP_TYPE_X 0x0A
+#define ACPI_BITPOSITION_SLEEP_ENABLE 0x0D
+
+#define ACPI_BITPOSITION_ARB_DISABLE 0x00
+
+/*****************************************************************************
+ *
+ * Resource descriptors
+ *
+ ****************************************************************************/
+
+/* resource_type values */
+
+#define ACPI_ADDRESS_TYPE_MEMORY_RANGE 0
+#define ACPI_ADDRESS_TYPE_IO_RANGE 1
+#define ACPI_ADDRESS_TYPE_BUS_NUMBER_RANGE 2
+
+/* Resource descriptor types and masks */
+
+#define ACPI_RESOURCE_NAME_LARGE 0x80
+#define ACPI_RESOURCE_NAME_SMALL 0x00
+
+#define ACPI_RESOURCE_NAME_SMALL_MASK 0x78 /* Bits 6:3 contain the type */
+#define ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK 0x07 /* Bits 2:0 contain the length */
+#define ACPI_RESOURCE_NAME_LARGE_MASK 0x7F /* Bits 6:0 contain the type */
+
+/*
+ * Small resource descriptor "names" as defined by the ACPI specification.
+ * Note: Bits 2:0 are used for the descriptor length
+ */
+#define ACPI_RESOURCE_NAME_IRQ 0x20
+#define ACPI_RESOURCE_NAME_DMA 0x28
+#define ACPI_RESOURCE_NAME_START_DEPENDENT 0x30
+#define ACPI_RESOURCE_NAME_END_DEPENDENT 0x38
+#define ACPI_RESOURCE_NAME_IO 0x40
+#define ACPI_RESOURCE_NAME_FIXED_IO 0x48
+#define ACPI_RESOURCE_NAME_RESERVED_S1 0x50
+#define ACPI_RESOURCE_NAME_RESERVED_S2 0x58
+#define ACPI_RESOURCE_NAME_RESERVED_S3 0x60
+#define ACPI_RESOURCE_NAME_RESERVED_S4 0x68
+#define ACPI_RESOURCE_NAME_VENDOR_SMALL 0x70
+#define ACPI_RESOURCE_NAME_END_TAG 0x78
+
+/*
+ * Large resource descriptor "names" as defined by the ACPI specification.
+ * Note: includes the Large Descriptor bit in bit[7]
+ */
+#define ACPI_RESOURCE_NAME_MEMORY24 0x81
+#define ACPI_RESOURCE_NAME_GENERIC_REGISTER 0x82
+#define ACPI_RESOURCE_NAME_RESERVED_L1 0x83
+#define ACPI_RESOURCE_NAME_VENDOR_LARGE 0x84
+#define ACPI_RESOURCE_NAME_MEMORY32 0x85
+#define ACPI_RESOURCE_NAME_FIXED_MEMORY32 0x86
+#define ACPI_RESOURCE_NAME_ADDRESS32 0x87
+#define ACPI_RESOURCE_NAME_ADDRESS16 0x88
+#define ACPI_RESOURCE_NAME_EXTENDED_IRQ 0x89
+#define ACPI_RESOURCE_NAME_ADDRESS64 0x8A
+#define ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 0x8B
+#define ACPI_RESOURCE_NAME_LARGE_MAX 0x8B
+
+/*****************************************************************************
+ *
+ * Miscellaneous
+ *
+ ****************************************************************************/
+
+#define ACPI_ASCII_ZERO 0x30
+
+/*****************************************************************************
+ *
+ * Debugger
+ *
+ ****************************************************************************/
+
+struct acpi_db_method_info {
+ acpi_handle main_thread_gate;
+ acpi_handle thread_complete_gate;
+ u32 *threads;
+ u32 num_threads;
+ u32 num_created;
+ u32 num_completed;
+
+ char *name;
+ u32 flags;
+ u32 num_loops;
+ char pathname[128];
+ char **args;
+
+ /*
+ * Arguments to be passed to method for the command
+ * Threads -
+ * the Number of threads, ID of current thread and
+ * Index of current thread inside all them created.
+ */
+ char init_args;
+ char *arguments[4];
+ char num_threads_str[11];
+ char id_of_thread_str[11];
+ char index_of_thread_str[11];
+};
+
+struct acpi_integrity_info {
+ u32 nodes;
+ u32 objects;
+};
+
+#define ACPI_DB_REDIRECTABLE_OUTPUT 0x01
+#define ACPI_DB_CONSOLE_OUTPUT 0x02
+#define ACPI_DB_DUPLICATE_OUTPUT 0x03
+
+/*****************************************************************************
+ *
+ * Debug
+ *
+ ****************************************************************************/
+
+/* Entry for a memory allocation (debug only) */
+
+#define ACPI_MEM_MALLOC 0
+#define ACPI_MEM_CALLOC 1
+#define ACPI_MAX_MODULE_NAME 16
+
+#define ACPI_COMMON_DEBUG_MEM_HEADER \
+ struct acpi_debug_mem_block *previous; \
+ struct acpi_debug_mem_block *next; \
+ u32 size; \
+ u32 component; \
+ u32 line; \
+ char module[ACPI_MAX_MODULE_NAME]; \
+ u8 alloc_type;
+
+struct acpi_debug_mem_header {
+ACPI_COMMON_DEBUG_MEM_HEADER};
+
+struct acpi_debug_mem_block {
+ ACPI_COMMON_DEBUG_MEM_HEADER u64 user_space;
+};
+
+#define ACPI_MEM_LIST_GLOBAL 0
+#define ACPI_MEM_LIST_NSNODE 1
+#define ACPI_MEM_LIST_MAX 1
+#define ACPI_NUM_MEM_LISTS 2
+
+#endif /* __ACLOCAL_H__ */
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
new file mode 100644
index 000000000000..9c127e8e2d6d
--- /dev/null
+++ b/drivers/acpi/acpica/acmacros.h
@@ -0,0 +1,577 @@
+/******************************************************************************
+ *
+ * Name: acmacros.h - C macros for the entire subsystem.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACMACROS_H__
+#define __ACMACROS_H__
+
+/*
+ * Extract data using a pointer. Any more than a byte and we
+ * get into potential aligment issues -- see the STORE macros below.
+ * Use with care.
+ */
+#define ACPI_GET8(ptr) *ACPI_CAST_PTR (u8, ptr)
+#define ACPI_GET16(ptr) *ACPI_CAST_PTR (u16, ptr)
+#define ACPI_GET32(ptr) *ACPI_CAST_PTR (u32, ptr)
+#define ACPI_GET64(ptr) *ACPI_CAST_PTR (u64, ptr)
+#define ACPI_SET8(ptr) *ACPI_CAST_PTR (u8, ptr)
+#define ACPI_SET16(ptr) *ACPI_CAST_PTR (u16, ptr)
+#define ACPI_SET32(ptr) *ACPI_CAST_PTR (u32, ptr)
+#define ACPI_SET64(ptr) *ACPI_CAST_PTR (u64, ptr)
+
+/*
+ * printf() format helpers
+ */
+
+/* Split 64-bit integer into two 32-bit values. Use with %8.8_x%8.8_x */
+
+#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i), ACPI_LODWORD(i)
+
+#if ACPI_MACHINE_WIDTH == 64
+#define ACPI_FORMAT_NATIVE_UINT(i) ACPI_FORMAT_UINT64(i)
+#else
+#define ACPI_FORMAT_NATIVE_UINT(i) 0, (i)
+#endif
+
+/*
+ * Macros for moving data around to/from buffers that are possibly unaligned.
+ * If the hardware supports the transfer of unaligned data, just do the store.
+ * Otherwise, we have to move one byte at a time.
+ */
+#ifdef ACPI_BIG_ENDIAN
+/*
+ * Macros for big-endian machines
+ */
+
+/* These macros reverse the bytes during the move, converting little-endian to big endian */
+
+ /* Big Endian <== Little Endian */
+ /* Hi...Lo Lo...Hi */
+/* 16-bit source, 16/32/64 destination */
+
+#define ACPI_MOVE_16_TO_16(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[1];\
+ (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[0];}
+
+#define ACPI_MOVE_16_TO_32(d, s) {(*(u32 *)(void *)(d))=0;\
+ ((u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\
+ ((u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];}
+
+#define ACPI_MOVE_16_TO_64(d, s) {(*(u64 *)(void *)(d))=0;\
+ ((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\
+ ((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];}
+
+/* 32-bit source, 16/32/64 destination */
+
+#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */
+
+#define ACPI_MOVE_32_TO_32(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[3];\
+ (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[2];\
+ (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\
+ (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];}
+
+#define ACPI_MOVE_32_TO_64(d, s) {(*(u64 *)(void *)(d))=0;\
+ ((u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[3];\
+ ((u8 *)(void *)(d))[5] = ((u8 *)(void *)(s))[2];\
+ ((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\
+ ((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];}
+
+/* 64-bit source, 16/32/64 destination */
+
+#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */
+
+#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */
+
+#define ACPI_MOVE_64_TO_64(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[7];\
+ (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[6];\
+ (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[5];\
+ (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[4];\
+ (( u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[3];\
+ (( u8 *)(void *)(d))[5] = ((u8 *)(void *)(s))[2];\
+ (( u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\
+ (( u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];}
+#else
+/*
+ * Macros for little-endian machines
+ */
+
+#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED
+
+/* The hardware supports unaligned transfers, just do the little-endian move */
+
+/* 16-bit source, 16/32/64 destination */
+
+#define ACPI_MOVE_16_TO_16(d, s) *(u16 *)(void *)(d) = *(u16 *)(void *)(s)
+#define ACPI_MOVE_16_TO_32(d, s) *(u32 *)(void *)(d) = *(u16 *)(void *)(s)
+#define ACPI_MOVE_16_TO_64(d, s) *(u64 *)(void *)(d) = *(u16 *)(void *)(s)
+
+/* 32-bit source, 16/32/64 destination */
+
+#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */
+#define ACPI_MOVE_32_TO_32(d, s) *(u32 *)(void *)(d) = *(u32 *)(void *)(s)
+#define ACPI_MOVE_32_TO_64(d, s) *(u64 *)(void *)(d) = *(u32 *)(void *)(s)
+
+/* 64-bit source, 16/32/64 destination */
+
+#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */
+#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */
+#define ACPI_MOVE_64_TO_64(d, s) *(u64 *)(void *)(d) = *(u64 *)(void *)(s)
+
+#else
+/*
+ * The hardware does not support unaligned transfers. We must move the
+ * data one byte at a time. These macros work whether the source or
+ * the destination (or both) is/are unaligned. (Little-endian move)
+ */
+
+/* 16-bit source, 16/32/64 destination */
+
+#define ACPI_MOVE_16_TO_16(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[0];\
+ (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[1];}
+
+#define ACPI_MOVE_16_TO_32(d, s) {(*(u32 *)(void *)(d)) = 0; ACPI_MOVE_16_TO_16(d, s);}
+#define ACPI_MOVE_16_TO_64(d, s) {(*(u64 *)(void *)(d)) = 0; ACPI_MOVE_16_TO_16(d, s);}
+
+/* 32-bit source, 16/32/64 destination */
+
+#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */
+
+#define ACPI_MOVE_32_TO_32(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[0];\
+ (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[1];\
+ (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[2];\
+ (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[3];}
+
+#define ACPI_MOVE_32_TO_64(d, s) {(*(u64 *)(void *)(d)) = 0; ACPI_MOVE_32_TO_32(d, s);}
+
+/* 64-bit source, 16/32/64 destination */
+
+#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */
+#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */
+#define ACPI_MOVE_64_TO_64(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[0];\
+ (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[1];\
+ (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[2];\
+ (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[3];\
+ (( u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[4];\
+ (( u8 *)(void *)(d))[5] = ((u8 *)(void *)(s))[5];\
+ (( u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[6];\
+ (( u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[7];}
+#endif
+#endif
+
+/* Macros based on machine integer width */
+
+#if ACPI_MACHINE_WIDTH == 32
+#define ACPI_MOVE_SIZE_TO_16(d, s) ACPI_MOVE_32_TO_16(d, s)
+
+#elif ACPI_MACHINE_WIDTH == 64
+#define ACPI_MOVE_SIZE_TO_16(d, s) ACPI_MOVE_64_TO_16(d, s)
+
+#else
+#error unknown ACPI_MACHINE_WIDTH
+#endif
+
+/*
+ * Fast power-of-two math macros for non-optimized compilers
+ */
+#define _ACPI_DIV(value, power_of2) ((u32) ((value) >> (power_of2)))
+#define _ACPI_MUL(value, power_of2) ((u32) ((value) << (power_of2)))
+#define _ACPI_MOD(value, divisor) ((u32) ((value) & ((divisor) -1)))
+
+#define ACPI_DIV_2(a) _ACPI_DIV(a, 1)
+#define ACPI_MUL_2(a) _ACPI_MUL(a, 1)
+#define ACPI_MOD_2(a) _ACPI_MOD(a, 2)
+
+#define ACPI_DIV_4(a) _ACPI_DIV(a, 2)
+#define ACPI_MUL_4(a) _ACPI_MUL(a, 2)
+#define ACPI_MOD_4(a) _ACPI_MOD(a, 4)
+
+#define ACPI_DIV_8(a) _ACPI_DIV(a, 3)
+#define ACPI_MUL_8(a) _ACPI_MUL(a, 3)
+#define ACPI_MOD_8(a) _ACPI_MOD(a, 8)
+
+#define ACPI_DIV_16(a) _ACPI_DIV(a, 4)
+#define ACPI_MUL_16(a) _ACPI_MUL(a, 4)
+#define ACPI_MOD_16(a) _ACPI_MOD(a, 16)
+
+#define ACPI_DIV_32(a) _ACPI_DIV(a, 5)
+#define ACPI_MUL_32(a) _ACPI_MUL(a, 5)
+#define ACPI_MOD_32(a) _ACPI_MOD(a, 32)
+
+/*
+ * Rounding macros (Power of two boundaries only)
+ */
+#define ACPI_ROUND_DOWN(value, boundary) (((acpi_size)(value)) & \
+ (~(((acpi_size) boundary)-1)))
+
+#define ACPI_ROUND_UP(value, boundary) ((((acpi_size)(value)) + \
+ (((acpi_size) boundary)-1)) & \
+ (~(((acpi_size) boundary)-1)))
+
+/* Note: sizeof(acpi_size) evaluates to either 4 or 8 (32- vs 64-bit mode) */
+
+#define ACPI_ROUND_DOWN_TO_32BIT(a) ACPI_ROUND_DOWN(a, 4)
+#define ACPI_ROUND_DOWN_TO_64BIT(a) ACPI_ROUND_DOWN(a, 8)
+#define ACPI_ROUND_DOWN_TO_NATIVE_WORD(a) ACPI_ROUND_DOWN(a, sizeof(acpi_size))
+
+#define ACPI_ROUND_UP_TO_32BIT(a) ACPI_ROUND_UP(a, 4)
+#define ACPI_ROUND_UP_TO_64BIT(a) ACPI_ROUND_UP(a, 8)
+#define ACPI_ROUND_UP_TO_NATIVE_WORD(a) ACPI_ROUND_UP(a, sizeof(acpi_size))
+
+#define ACPI_ROUND_BITS_UP_TO_BYTES(a) ACPI_DIV_8((a) + 7)
+#define ACPI_ROUND_BITS_DOWN_TO_BYTES(a) ACPI_DIV_8((a))
+
+#define ACPI_ROUND_UP_TO_1K(a) (((a) + 1023) >> 10)
+
+/* Generic (non-power-of-two) rounding */
+
+#define ACPI_ROUND_UP_TO(value, boundary) (((value) + ((boundary)-1)) / (boundary))
+
+#define ACPI_IS_MISALIGNED(value) (((acpi_size) value) & (sizeof(acpi_size)-1))
+
+/*
+ * Bitmask creation
+ * Bit positions start at zero.
+ * MASK_BITS_ABOVE creates a mask starting AT the position and above
+ * MASK_BITS_BELOW creates a mask starting one bit BELOW the position
+ */
+#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_INTEGER_MAX) << ((u32) (position))))
+#define ACPI_MASK_BITS_BELOW(position) ((ACPI_INTEGER_MAX) << ((u32) (position)))
+
+/* Bitfields within ACPI registers */
+
+#define ACPI_REGISTER_PREPARE_BITS(val, pos, mask) ((val << pos) & mask)
+#define ACPI_REGISTER_INSERT_VALUE(reg, pos, mask, val) reg = (reg & (~(mask))) | ACPI_REGISTER_PREPARE_BITS(val, pos, mask)
+
+#define ACPI_INSERT_BITS(target, mask, source) target = ((target & (~(mask))) | (source & mask))
+
+/*
+ * A struct acpi_namespace_node can appear in some contexts
+ * where a pointer to a union acpi_operand_object can also
+ * appear. This macro is used to distinguish them.
+ *
+ * The "Descriptor" field is the first field in both structures.
+ */
+#define ACPI_GET_DESCRIPTOR_TYPE(d) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type)
+#define ACPI_SET_DESCRIPTOR_TYPE(d, t) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type = t)
+
+/* Macro to test the object type */
+
+#define ACPI_GET_OBJECT_TYPE(d) (((union acpi_operand_object *)(void *)(d))->common.type)
+
+/*
+ * Macros for the master AML opcode table
+ */
+#if defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUG_OUTPUT)
+#define ACPI_OP(name, Pargs, Iargs, obj_type, class, type, flags) \
+ {name, (u32)(Pargs), (u32)(Iargs), (u32)(flags), obj_type, class, type}
+#else
+#define ACPI_OP(name, Pargs, Iargs, obj_type, class, type, flags) \
+ {(u32)(Pargs), (u32)(Iargs), (u32)(flags), obj_type, class, type}
+#endif
+
+#define ARG_TYPE_WIDTH 5
+#define ARG_1(x) ((u32)(x))
+#define ARG_2(x) ((u32)(x) << (1 * ARG_TYPE_WIDTH))
+#define ARG_3(x) ((u32)(x) << (2 * ARG_TYPE_WIDTH))
+#define ARG_4(x) ((u32)(x) << (3 * ARG_TYPE_WIDTH))
+#define ARG_5(x) ((u32)(x) << (4 * ARG_TYPE_WIDTH))
+#define ARG_6(x) ((u32)(x) << (5 * ARG_TYPE_WIDTH))
+
+#define ARGI_LIST1(a) (ARG_1(a))
+#define ARGI_LIST2(a, b) (ARG_1(b)|ARG_2(a))
+#define ARGI_LIST3(a, b, c) (ARG_1(c)|ARG_2(b)|ARG_3(a))
+#define ARGI_LIST4(a, b, c, d) (ARG_1(d)|ARG_2(c)|ARG_3(b)|ARG_4(a))
+#define ARGI_LIST5(a, b, c, d, e) (ARG_1(e)|ARG_2(d)|ARG_3(c)|ARG_4(b)|ARG_5(a))
+#define ARGI_LIST6(a, b, c, d, e, f) (ARG_1(f)|ARG_2(e)|ARG_3(d)|ARG_4(c)|ARG_5(b)|ARG_6(a))
+
+#define ARGP_LIST1(a) (ARG_1(a))
+#define ARGP_LIST2(a, b) (ARG_1(a)|ARG_2(b))
+#define ARGP_LIST3(a, b, c) (ARG_1(a)|ARG_2(b)|ARG_3(c))
+#define ARGP_LIST4(a, b, c, d) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d))
+#define ARGP_LIST5(a, b, c, d, e) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e))
+#define ARGP_LIST6(a, b, c, d, e, f) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)|ARG_6(f))
+
+#define GET_CURRENT_ARG_TYPE(list) (list & ((u32) 0x1F))
+#define INCREMENT_ARG_LIST(list) (list >>= ((u32) ARG_TYPE_WIDTH))
+
+/*
+ * Ascii error messages can be configured out
+ */
+#ifndef ACPI_NO_ERROR_MESSAGES
+
+/*
+ * Error reporting. Callers module and line number are inserted by AE_INFO,
+ * the plist contains a set of parens to allow variable-length lists.
+ * These macros are used for both the debug and non-debug versions of the code.
+ */
+#define ACPI_ERROR_NAMESPACE(s, e) acpi_ns_report_error (AE_INFO, s, e);
+#define ACPI_ERROR_METHOD(s, n, p, e) acpi_ns_report_method_error (AE_INFO, s, n, p, e);
+
+#else
+
+/* No error messages */
+
+#define ACPI_ERROR_NAMESPACE(s, e)
+#define ACPI_ERROR_METHOD(s, n, p, e)
+#endif /* ACPI_NO_ERROR_MESSAGES */
+
+/*
+ * Debug macros that are conditionally compiled
+ */
+#ifdef ACPI_DEBUG_OUTPUT
+
+/*
+ * Function entry tracing
+ */
+#ifdef CONFIG_ACPI_DEBUG_FUNC_TRACE
+
+#define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \
+ acpi_ut_trace(ACPI_DEBUG_PARAMETERS)
+#define ACPI_FUNCTION_TRACE_PTR(a, b) ACPI_FUNCTION_NAME(a) \
+ acpi_ut_trace_ptr(ACPI_DEBUG_PARAMETERS, (void *)b)
+#define ACPI_FUNCTION_TRACE_U32(a, b) ACPI_FUNCTION_NAME(a) \
+ acpi_ut_trace_u32(ACPI_DEBUG_PARAMETERS, (u32)b)
+#define ACPI_FUNCTION_TRACE_STR(a, b) ACPI_FUNCTION_NAME(a) \
+ acpi_ut_trace_str(ACPI_DEBUG_PARAMETERS, (char *)b)
+
+#define ACPI_FUNCTION_ENTRY() acpi_ut_track_stack_ptr()
+
+/*
+ * Function exit tracing.
+ * WARNING: These macros include a return statement. This is usually considered
+ * bad form, but having a separate exit macro is very ugly and difficult to maintain.
+ * One of the FUNCTION_TRACE macros above must be used in conjunction with these macros
+ * so that "_AcpiFunctionName" is defined.
+ *
+ * Note: the DO_WHILE0 macro is used to prevent some compilers from complaining
+ * about these constructs.
+ */
+#ifdef ACPI_USE_DO_WHILE_0
+#define ACPI_DO_WHILE0(a) do a while(0)
+#else
+#define ACPI_DO_WHILE0(a) a
+#endif
+
+#define return_VOID ACPI_DO_WHILE0 ({ \
+ acpi_ut_exit (ACPI_DEBUG_PARAMETERS); \
+ return;})
+/*
+ * There are two versions of most of the return macros. The default version is
+ * safer, since it avoids side-effects by guaranteeing that the argument will
+ * not be evaluated twice.
+ *
+ * A less-safe version of the macros is provided for optional use if the
+ * compiler uses excessive CPU stack (for example, this may happen in the
+ * debug case if code optimzation is disabled.)
+ */
+#ifndef ACPI_SIMPLE_RETURN_MACROS
+
+#define return_ACPI_STATUS(s) ACPI_DO_WHILE0 ({ \
+ register acpi_status _s = (s); \
+ acpi_ut_status_exit (ACPI_DEBUG_PARAMETERS, _s); \
+ return (_s); })
+#define return_PTR(s) ACPI_DO_WHILE0 ({ \
+ register void *_s = (void *) (s); \
+ acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) _s); \
+ return (_s); })
+#define return_VALUE(s) ACPI_DO_WHILE0 ({ \
+ register acpi_integer _s = (s); \
+ acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, _s); \
+ return (_s); })
+#define return_UINT8(s) ACPI_DO_WHILE0 ({ \
+ register u8 _s = (u8) (s); \
+ acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) _s); \
+ return (_s); })
+#define return_UINT32(s) ACPI_DO_WHILE0 ({ \
+ register u32 _s = (u32) (s); \
+ acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) _s); \
+ return (_s); })
+#else /* Use original less-safe macros */
+
+#define return_ACPI_STATUS(s) ACPI_DO_WHILE0 ({ \
+ acpi_ut_status_exit (ACPI_DEBUG_PARAMETERS, (s)); \
+ return((s)); })
+#define return_PTR(s) ACPI_DO_WHILE0 ({ \
+ acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) (s)); \
+ return((s)); })
+#define return_VALUE(s) ACPI_DO_WHILE0 ({ \
+ acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) (s)); \
+ return((s)); })
+#define return_UINT8(s) return_VALUE(s)
+#define return_UINT32(s) return_VALUE(s)
+
+#endif /* ACPI_SIMPLE_RETURN_MACROS */
+
+#else /* !CONFIG_ACPI_DEBUG_FUNC_TRACE */
+
+#define ACPI_FUNCTION_TRACE(a)
+#define ACPI_FUNCTION_TRACE_PTR(a,b)
+#define ACPI_FUNCTION_TRACE_U32(a,b)
+#define ACPI_FUNCTION_TRACE_STR(a,b)
+#define ACPI_FUNCTION_EXIT
+#define ACPI_FUNCTION_STATUS_EXIT(s)
+#define ACPI_FUNCTION_VALUE_EXIT(s)
+#define ACPI_FUNCTION_TRACE(a)
+#define ACPI_FUNCTION_ENTRY()
+
+#define return_VOID return
+#define return_ACPI_STATUS(s) return(s)
+#define return_VALUE(s) return(s)
+#define return_UINT8(s) return(s)
+#define return_UINT32(s) return(s)
+#define return_PTR(s) return(s)
+
+#endif /* CONFIG_ACPI_DEBUG_FUNC_TRACE */
+
+/* Conditional execution */
+
+#define ACPI_DEBUG_EXEC(a) a
+#define ACPI_NORMAL_EXEC(a)
+
+#define ACPI_DEBUG_DEFINE(a) a;
+#define ACPI_DEBUG_ONLY_MEMBERS(a) a;
+#define _VERBOSE_STRUCTURES
+
+/* Stack and buffer dumping */
+
+#define ACPI_DUMP_STACK_ENTRY(a) acpi_ex_dump_operand((a), 0)
+#define ACPI_DUMP_OPERANDS(a, b, c) acpi_ex_dump_operands(a, b, c)
+
+#define ACPI_DUMP_ENTRY(a, b) acpi_ns_dump_entry (a, b)
+#define ACPI_DUMP_PATHNAME(a, b, c, d) acpi_ns_dump_pathname(a, b, c, d)
+#define ACPI_DUMP_RESOURCE_LIST(a) acpi_rs_dump_resource_list(a)
+#define ACPI_DUMP_BUFFER(a, b) acpi_ut_dump_buffer((u8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT)
+
+#else
+/*
+ * This is the non-debug case -- make everything go away,
+ * leaving no executable debug code!
+ */
+#define ACPI_DEBUG_EXEC(a)
+#define ACPI_NORMAL_EXEC(a) a;
+
+#define ACPI_DEBUG_DEFINE(a) do { } while(0)
+#define ACPI_DEBUG_ONLY_MEMBERS(a) do { } while(0)
+#define ACPI_FUNCTION_TRACE(a) do { } while(0)
+#define ACPI_FUNCTION_TRACE_PTR(a, b) do { } while(0)
+#define ACPI_FUNCTION_TRACE_U32(a, b) do { } while(0)
+#define ACPI_FUNCTION_TRACE_STR(a, b) do { } while(0)
+#define ACPI_FUNCTION_EXIT do { } while(0)
+#define ACPI_FUNCTION_STATUS_EXIT(s) do { } while(0)
+#define ACPI_FUNCTION_VALUE_EXIT(s) do { } while(0)
+#define ACPI_FUNCTION_ENTRY() do { } while(0)
+#define ACPI_DUMP_STACK_ENTRY(a) do { } while(0)
+#define ACPI_DUMP_OPERANDS(a, b, c) do { } while(0)
+#define ACPI_DUMP_ENTRY(a, b) do { } while(0)
+#define ACPI_DUMP_TABLES(a, b) do { } while(0)
+#define ACPI_DUMP_PATHNAME(a, b, c, d) do { } while(0)
+#define ACPI_DUMP_RESOURCE_LIST(a) do { } while(0)
+#define ACPI_DUMP_BUFFER(a, b) do { } while(0)
+
+#define return_VOID return
+#define return_ACPI_STATUS(s) return(s)
+#define return_VALUE(s) return(s)
+#define return_UINT8(s) return(s)
+#define return_UINT32(s) return(s)
+#define return_PTR(s) return(s)
+
+#endif /* ACPI_DEBUG_OUTPUT */
+
+/*
+ * Some code only gets executed when the debugger is built in.
+ * Note that this is entirely independent of whether the
+ * DEBUG_PRINT stuff (set by ACPI_DEBUG_OUTPUT) is on, or not.
+ */
+#ifdef ACPI_DEBUGGER
+#define ACPI_DEBUGGER_EXEC(a) a
+#else
+#define ACPI_DEBUGGER_EXEC(a)
+#endif
+
+#ifdef ACPI_DEBUG_OUTPUT
+/*
+ * 1) Set name to blanks
+ * 2) Copy the object name
+ */
+#define ACPI_ADD_OBJECT_NAME(a,b) ACPI_MEMSET (a->common.name, ' ', sizeof (a->common.name));\
+ ACPI_STRNCPY (a->common.name, acpi_gbl_ns_type_names[b], sizeof (a->common.name))
+#else
+
+#define ACPI_ADD_OBJECT_NAME(a,b)
+#endif
+
+/*
+ * Memory allocation tracking (DEBUG ONLY)
+ */
+#define ACPI_MEM_PARAMETERS _COMPONENT, _acpi_module_name, __LINE__
+
+#ifndef ACPI_DBG_TRACK_ALLOCATIONS
+
+/* Memory allocation */
+
+#ifndef ACPI_ALLOCATE
+#define ACPI_ALLOCATE(a) acpi_ut_allocate((acpi_size)(a), ACPI_MEM_PARAMETERS)
+#endif
+#ifndef ACPI_ALLOCATE_ZEROED
+#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed((acpi_size)(a), ACPI_MEM_PARAMETERS)
+#endif
+#ifndef ACPI_FREE
+#define ACPI_FREE(a) acpio_os_free(a)
+#endif
+#define ACPI_MEM_TRACKING(a)
+
+#else
+
+/* Memory allocation */
+
+#define ACPI_ALLOCATE(a) acpi_ut_allocate_and_track((acpi_size)(a), ACPI_MEM_PARAMETERS)
+#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed_and_track((acpi_size)(a), ACPI_MEM_PARAMETERS)
+#define ACPI_FREE(a) acpi_ut_free_and_track(a, ACPI_MEM_PARAMETERS)
+#define ACPI_MEM_TRACKING(a) a
+
+#endif /* ACPI_DBG_TRACK_ALLOCATIONS */
+
+/* Preemption point */
+#ifndef ACPI_PREEMPTION_POINT
+#define ACPI_PREEMPTION_POINT() /* no preemption */
+#endif
+
+#endif /* ACMACROS_H */
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
new file mode 100644
index 000000000000..46cb5b46d280
--- /dev/null
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -0,0 +1,324 @@
+/******************************************************************************
+ *
+ * Name: acnamesp.h - Namespace subcomponent prototypes and defines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACNAMESP_H__
+#define __ACNAMESP_H__
+
+/* To search the entire name space, pass this as search_base */
+
+#define ACPI_NS_ALL ((acpi_handle)0)
+
+/*
+ * Elements of acpi_ns_properties are bit significant
+ * and should be one-to-one with values of acpi_object_type
+ */
+#define ACPI_NS_NORMAL 0
+#define ACPI_NS_NEWSCOPE 1 /* a definition of this type opens a name scope */
+#define ACPI_NS_LOCAL 2 /* suppress search of enclosing scopes */
+
+/* Flags for acpi_ns_lookup, acpi_ns_search_and_enter */
+
+#define ACPI_NS_NO_UPSEARCH 0
+#define ACPI_NS_SEARCH_PARENT 0x01
+#define ACPI_NS_DONT_OPEN_SCOPE 0x02
+#define ACPI_NS_NO_PEER_SEARCH 0x04
+#define ACPI_NS_ERROR_IF_FOUND 0x08
+#define ACPI_NS_PREFIX_IS_SCOPE 0x10
+#define ACPI_NS_EXTERNAL 0x20
+#define ACPI_NS_TEMPORARY 0x40
+
+/* Flags for acpi_ns_walk_namespace */
+
+#define ACPI_NS_WALK_NO_UNLOCK 0
+#define ACPI_NS_WALK_UNLOCK 0x01
+#define ACPI_NS_WALK_TEMP_NODES 0x02
+
+/*
+ * nsinit - Namespace initialization
+ */
+acpi_status acpi_ns_initialize_objects(void);
+
+acpi_status acpi_ns_initialize_devices(void);
+
+/*
+ * nsload - Namespace loading
+ */
+acpi_status acpi_ns_load_namespace(void);
+
+acpi_status
+acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node);
+
+/*
+ * nswalk - walk the namespace
+ */
+acpi_status
+acpi_ns_walk_namespace(acpi_object_type type,
+ acpi_handle start_object,
+ u32 max_depth,
+ u32 flags,
+ acpi_walk_callback user_function,
+ void *context, void **return_value);
+
+struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node
+ *parent, struct acpi_namespace_node
+ *child);
+
+/*
+ * nsparse - table parsing
+ */
+acpi_status
+acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node);
+
+acpi_status
+acpi_ns_one_complete_parse(u32 pass_number,
+ u32 table_index,
+ struct acpi_namespace_node *start_node);
+
+/*
+ * nsaccess - Top-level namespace access
+ */
+acpi_status acpi_ns_root_initialize(void);
+
+acpi_status
+acpi_ns_lookup(union acpi_generic_state *scope_info,
+ char *name,
+ acpi_object_type type,
+ acpi_interpreter_mode interpreter_mode,
+ u32 flags,
+ struct acpi_walk_state *walk_state,
+ struct acpi_namespace_node **ret_node);
+
+/*
+ * nsalloc - Named object allocation/deallocation
+ */
+struct acpi_namespace_node *acpi_ns_create_node(u32 name);
+
+void acpi_ns_delete_node(struct acpi_namespace_node *node);
+
+void
+acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_handle);
+
+void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id);
+
+void acpi_ns_detach_object(struct acpi_namespace_node *node);
+
+void acpi_ns_delete_children(struct acpi_namespace_node *parent);
+
+int acpi_ns_compare_names(char *name1, char *name2);
+
+/*
+ * nsdump - Namespace dump/print utilities
+ */
+#ifdef ACPI_FUTURE_USAGE
+void acpi_ns_dump_tables(acpi_handle search_base, u32 max_depth);
+#endif /* ACPI_FUTURE_USAGE */
+
+void acpi_ns_dump_entry(acpi_handle handle, u32 debug_level);
+
+void
+acpi_ns_dump_pathname(acpi_handle handle, char *msg, u32 level, u32 component);
+
+void acpi_ns_print_pathname(u32 num_segments, char *pathname);
+
+acpi_status
+acpi_ns_dump_one_object(acpi_handle obj_handle,
+ u32 level, void *context, void **return_value);
+
+#ifdef ACPI_FUTURE_USAGE
+void
+acpi_ns_dump_objects(acpi_object_type type,
+ u8 display_type,
+ u32 max_depth,
+ acpi_owner_id owner_id, acpi_handle start_handle);
+#endif /* ACPI_FUTURE_USAGE */
+
+/*
+ * nseval - Namespace evaluation functions
+ */
+acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info);
+
+/*
+ * nspredef - Support for predefined/reserved names
+ */
+acpi_status
+acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
+ u32 user_param_count,
+ acpi_status return_status,
+ union acpi_operand_object **return_object);
+
+const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
+ acpi_namespace_node
+ *node);
+
+void
+acpi_ns_check_parameter_count(char *pathname,
+ struct acpi_namespace_node *node,
+ u32 user_param_count,
+ const union acpi_predefined_info *info);
+
+/*
+ * nsnames - Name and Scope manipulation
+ */
+u32 acpi_ns_opens_scope(acpi_object_type type);
+
+acpi_status
+acpi_ns_build_external_path(struct acpi_namespace_node *node,
+ acpi_size size, char *name_buffer);
+
+char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node);
+
+char *acpi_ns_name_of_current_scope(struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ns_handle_to_pathname(acpi_handle target_handle,
+ struct acpi_buffer *buffer);
+
+u8
+acpi_ns_pattern_match(struct acpi_namespace_node *obj_node, char *search_for);
+
+acpi_status
+acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
+ const char *external_pathname,
+ u32 flags, struct acpi_namespace_node **out_node);
+
+acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node);
+
+/*
+ * nsobject - Object management for namespace nodes
+ */
+acpi_status
+acpi_ns_attach_object(struct acpi_namespace_node *node,
+ union acpi_operand_object *object, acpi_object_type type);
+
+union acpi_operand_object *acpi_ns_get_attached_object(struct
+ acpi_namespace_node
+ *node);
+
+union acpi_operand_object *acpi_ns_get_secondary_object(union
+ acpi_operand_object
+ *obj_desc);
+
+acpi_status
+acpi_ns_attach_data(struct acpi_namespace_node *node,
+ acpi_object_handler handler, void *data);
+
+acpi_status
+acpi_ns_detach_data(struct acpi_namespace_node *node,
+ acpi_object_handler handler);
+
+acpi_status
+acpi_ns_get_attached_data(struct acpi_namespace_node *node,
+ acpi_object_handler handler, void **data);
+
+/*
+ * nssearch - Namespace searching and entry
+ */
+acpi_status
+acpi_ns_search_and_enter(u32 entry_name,
+ struct acpi_walk_state *walk_state,
+ struct acpi_namespace_node *node,
+ acpi_interpreter_mode interpreter_mode,
+ acpi_object_type type,
+ u32 flags, struct acpi_namespace_node **ret_node);
+
+acpi_status
+acpi_ns_search_one_scope(u32 entry_name,
+ struct acpi_namespace_node *node,
+ acpi_object_type type,
+ struct acpi_namespace_node **ret_node);
+
+void
+acpi_ns_install_node(struct acpi_walk_state *walk_state,
+ struct acpi_namespace_node *parent_node,
+ struct acpi_namespace_node *node, acpi_object_type type);
+
+/*
+ * nsutils - Utility functions
+ */
+u8 acpi_ns_valid_root_prefix(char prefix);
+
+acpi_object_type acpi_ns_get_type(struct acpi_namespace_node *node);
+
+u32 acpi_ns_local(acpi_object_type type);
+
+void
+acpi_ns_report_error(const char *module_name,
+ u32 line_number,
+ const char *internal_name, acpi_status lookup_status);
+
+void
+acpi_ns_report_method_error(const char *module_name,
+ u32 line_number,
+ const char *message,
+ struct acpi_namespace_node *node,
+ const char *path, acpi_status lookup_status);
+
+void
+acpi_ns_print_node_pathname(struct acpi_namespace_node *node, const char *msg);
+
+acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info);
+
+void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info);
+
+acpi_status
+acpi_ns_internalize_name(const char *dotted_name, char **converted_name);
+
+acpi_status
+acpi_ns_externalize_name(u32 internal_name_length,
+ const char *internal_name,
+ u32 * converted_name_length, char **converted_name);
+
+struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle);
+
+acpi_handle acpi_ns_convert_entry_to_handle(struct acpi_namespace_node *node);
+
+void acpi_ns_terminate(void);
+
+struct acpi_namespace_node *acpi_ns_get_parent_node(struct acpi_namespace_node
+ *node);
+
+struct acpi_namespace_node *acpi_ns_get_next_valid_node(struct
+ acpi_namespace_node
+ *node);
+
+#endif /* __ACNAMESP_H__ */
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
new file mode 100644
index 000000000000..eb6f038b03d9
--- /dev/null
+++ b/drivers/acpi/acpica/acobject.h
@@ -0,0 +1,446 @@
+
+/******************************************************************************
+ *
+ * Name: acobject.h - Definition of union acpi_operand_object (Internal object only)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 _ACOBJECT_H
+#define _ACOBJECT_H
+
+/* acpisrc:struct_defs -- for acpisrc conversion */
+
+/*
+ * The union acpi_operand_object is used to pass AML operands from the dispatcher
+ * to the interpreter, and to keep track of the various handlers such as
+ * address space handlers and notify handlers. The object is a constant
+ * size in order to allow it to be cached and reused.
+ *
+ * Note: The object is optimized to be aligned and will not work if it is
+ * byte-packed.
+ */
+#if ACPI_MACHINE_WIDTH == 64
+#pragma pack(8)
+#else
+#pragma pack(4)
+#endif
+
+/*******************************************************************************
+ *
+ * Common Descriptors
+ *
+ ******************************************************************************/
+
+/*
+ * Common area for all objects.
+ *
+ * descriptor_type is used to differentiate between internal descriptors, and
+ * must be in the same place across all descriptors
+ *
+ * Note: The descriptor_type and Type fields must appear in the identical
+ * position in both the struct acpi_namespace_node and union acpi_operand_object
+ * structures.
+ */
+#define ACPI_OBJECT_COMMON_HEADER \
+ union acpi_operand_object *next_object; /* Objects linked to parent NS node */\
+ u8 descriptor_type; /* To differentiate various internal objs */\
+ u8 type; /* acpi_object_type */\
+ u16 reference_count; /* For object deletion management */\
+ u8 flags;
+ /*
+ * Note: There are 3 bytes available here before the
+ * next natural alignment boundary (for both 32/64 cases)
+ */
+
+/* Values for Flag byte above */
+
+#define AOPOBJ_AML_CONSTANT 0x01
+#define AOPOBJ_STATIC_POINTER 0x02
+#define AOPOBJ_DATA_VALID 0x04
+#define AOPOBJ_OBJECT_INITIALIZED 0x08
+#define AOPOBJ_SETUP_COMPLETE 0x10
+#define AOPOBJ_SINGLE_DATUM 0x20
+#define AOPOBJ_INVALID 0x40 /* Used if host OS won't allow an op_region address */
+
+/******************************************************************************
+ *
+ * Basic data types
+ *
+ *****************************************************************************/
+
+struct acpi_object_common {
+ACPI_OBJECT_COMMON_HEADER};
+
+struct acpi_object_integer {
+ ACPI_OBJECT_COMMON_HEADER u8 fill[3]; /* Prevent warning on some compilers */
+ acpi_integer value;
+};
+
+/*
+ * Note: The String and Buffer object must be identical through the Pointer
+ * and length elements. There is code that depends on this.
+ *
+ * Fields common to both Strings and Buffers
+ */
+#define ACPI_COMMON_BUFFER_INFO(_type) \
+ _type *pointer; \
+ u32 length;
+
+struct acpi_object_string { /* Null terminated, ASCII characters only */
+ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO(char) /* String in AML stream or allocated string */
+};
+
+struct acpi_object_buffer {
+ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO(u8) /* Buffer in AML stream or allocated buffer */
+ u32 aml_length;
+ u8 *aml_start;
+ struct acpi_namespace_node *node; /* Link back to parent node */
+};
+
+struct acpi_object_package {
+ ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Link back to parent node */
+ union acpi_operand_object **elements; /* Array of pointers to acpi_objects */
+ u8 *aml_start;
+ u32 aml_length;
+ u32 count; /* # of elements in package */
+};
+
+/******************************************************************************
+ *
+ * Complex data types
+ *
+ *****************************************************************************/
+
+struct acpi_object_event {
+ ACPI_OBJECT_COMMON_HEADER acpi_semaphore os_semaphore; /* Actual OS synchronization object */
+};
+
+struct acpi_object_mutex {
+ ACPI_OBJECT_COMMON_HEADER u8 sync_level; /* 0-15, specified in Mutex() call */
+ u16 acquisition_depth; /* Allow multiple Acquires, same thread */
+ acpi_mutex os_mutex; /* Actual OS synchronization object */
+ acpi_thread_id thread_id; /* Current owner of the mutex */
+ struct acpi_thread_state *owner_thread; /* Current owner of the mutex */
+ union acpi_operand_object *prev; /* Link for list of acquired mutexes */
+ union acpi_operand_object *next; /* Link for list of acquired mutexes */
+ struct acpi_namespace_node *node; /* Containing namespace node */
+ u8 original_sync_level; /* Owner's original sync level (0-15) */
+};
+
+struct acpi_object_region {
+ ACPI_OBJECT_COMMON_HEADER u8 space_id;
+ struct acpi_namespace_node *node; /* Containing namespace node */
+ union acpi_operand_object *handler; /* Handler for region access */
+ union acpi_operand_object *next;
+ acpi_physical_address address;
+ u32 length;
+};
+
+struct acpi_object_method {
+ ACPI_OBJECT_COMMON_HEADER u8 method_flags;
+ u8 param_count;
+ u8 sync_level;
+ union acpi_operand_object *mutex;
+ u8 *aml_start;
+ ACPI_INTERNAL_METHOD implementation;
+ u32 aml_length;
+ u8 thread_count;
+ acpi_owner_id owner_id;
+};
+
+/******************************************************************************
+ *
+ * Objects that can be notified. All share a common notify_info area.
+ *
+ *****************************************************************************/
+
+/*
+ * Common fields for objects that support ASL notifications
+ */
+#define ACPI_COMMON_NOTIFY_INFO \
+ union acpi_operand_object *system_notify; /* Handler for system notifies */\
+ union acpi_operand_object *device_notify; /* Handler for driver notifies */\
+ union acpi_operand_object *handler; /* Handler for Address space */
+
+struct acpi_object_notify_common { /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */
+ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO};
+
+struct acpi_object_device {
+ ACPI_OBJECT_COMMON_HEADER
+ ACPI_COMMON_NOTIFY_INFO struct acpi_gpe_block_info *gpe_block;
+};
+
+struct acpi_object_power_resource {
+ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO u32 system_level;
+ u32 resource_order;
+};
+
+struct acpi_object_processor {
+ ACPI_OBJECT_COMMON_HEADER
+ /* The next two fields take advantage of the 3-byte space before NOTIFY_INFO */
+ u8 proc_id;
+ u8 length;
+ ACPI_COMMON_NOTIFY_INFO acpi_io_address address;
+};
+
+struct acpi_object_thermal_zone {
+ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO};
+
+/******************************************************************************
+ *
+ * Fields. All share a common header/info field.
+ *
+ *****************************************************************************/
+
+/*
+ * Common bitfield for the field objects
+ * "Field Datum" -- a datum from the actual field object
+ * "Buffer Datum" -- a datum from a user buffer, read from or to be written to the field
+ */
+#define ACPI_COMMON_FIELD_INFO \
+ u8 field_flags; /* Access, update, and lock bits */\
+ u8 attribute; /* From access_as keyword */\
+ u8 access_byte_width; /* Read/Write size in bytes */\
+ struct acpi_namespace_node *node; /* Link back to parent node */\
+ u32 bit_length; /* Length of field in bits */\
+ u32 base_byte_offset; /* Byte offset within containing object */\
+ u32 value; /* Value to store into the Bank or Index register */\
+ u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */\
+ u8 access_bit_width; /* Read/Write size in bits (8-64) */
+
+struct acpi_object_field_common { /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */
+ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Parent Operation Region object (REGION/BANK fields only) */
+};
+
+struct acpi_object_region_field {
+ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Containing op_region object */
+};
+
+struct acpi_object_bank_field {
+ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Containing op_region object */
+ union acpi_operand_object *bank_obj; /* bank_select Register object */
+};
+
+struct acpi_object_index_field {
+ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO
+ /*
+ * No "RegionObj" pointer needed since the Index and Data registers
+ * are each field definitions unto themselves.
+ */
+ union acpi_operand_object *index_obj; /* Index register */
+ union acpi_operand_object *data_obj; /* Data register */
+};
+
+/* The buffer_field is different in that it is part of a Buffer, not an op_region */
+
+struct acpi_object_buffer_field {
+ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *buffer_obj; /* Containing Buffer object */
+};
+
+/******************************************************************************
+ *
+ * Objects for handlers
+ *
+ *****************************************************************************/
+
+struct acpi_object_notify_handler {
+ ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Parent device */
+ acpi_notify_handler handler;
+ void *context;
+};
+
+struct acpi_object_addr_handler {
+ ACPI_OBJECT_COMMON_HEADER u8 space_id;
+ u8 handler_flags;
+ acpi_adr_space_handler handler;
+ struct acpi_namespace_node *node; /* Parent device */
+ void *context;
+ acpi_adr_space_setup setup;
+ union acpi_operand_object *region_list; /* regions using this handler */
+ union acpi_operand_object *next;
+};
+
+/* Flags for address handler (handler_flags) */
+
+#define ACPI_ADDR_HANDLER_DEFAULT_INSTALLED 0x01
+
+/******************************************************************************
+ *
+ * Special internal objects
+ *
+ *****************************************************************************/
+
+/*
+ * The Reference object is used for these opcodes:
+ * Arg[0-6], Local[0-7], index_op, name_op, ref_of_op, load_op, load_table_op, debug_op
+ * The Reference.Class differentiates these types.
+ */
+struct acpi_object_reference {
+ ACPI_OBJECT_COMMON_HEADER u8 class; /* Reference Class */
+ u8 target_type; /* Used for Index Op */
+ u8 reserved;
+ void *object; /* name_op=>HANDLE to obj, index_op=>union acpi_operand_object */
+ struct acpi_namespace_node *node; /* ref_of or Namepath */
+ union acpi_operand_object **where; /* Target of Index */
+ u32 value; /* Used for Local/Arg/Index/ddb_handle */
+};
+
+/* Values for Reference.Class above */
+
+typedef enum {
+ ACPI_REFCLASS_LOCAL = 0, /* Method local */
+ ACPI_REFCLASS_ARG = 1, /* Method argument */
+ ACPI_REFCLASS_REFOF = 2, /* Result of ref_of() TBD: Split to Ref/Node and Ref/operand_obj? */
+ ACPI_REFCLASS_INDEX = 3, /* Result of Index() */
+ ACPI_REFCLASS_TABLE = 4, /* ddb_handle - Load(), load_table() */
+ ACPI_REFCLASS_NAME = 5, /* Reference to a named object */
+ ACPI_REFCLASS_DEBUG = 6, /* Debug object */
+
+ ACPI_REFCLASS_MAX = 6
+} ACPI_REFERENCE_CLASSES;
+
+/*
+ * Extra object is used as additional storage for types that
+ * have AML code in their declarations (term_args) that must be
+ * evaluated at run time.
+ *
+ * Currently: Region and field_unit types
+ */
+struct acpi_object_extra {
+ ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *method_REG; /* _REG method for this region (if any) */
+ void *region_context; /* Region-specific data */
+ u8 *aml_start;
+ u32 aml_length;
+};
+
+/* Additional data that can be attached to namespace nodes */
+
+struct acpi_object_data {
+ ACPI_OBJECT_COMMON_HEADER acpi_object_handler handler;
+ void *pointer;
+};
+
+/* Structure used when objects are cached for reuse */
+
+struct acpi_object_cache_list {
+ ACPI_OBJECT_COMMON_HEADER union acpi_operand_object *next; /* Link for object cache and internal lists */
+};
+
+/******************************************************************************
+ *
+ * union acpi_operand_object Descriptor - a giant union of all of the above
+ *
+ *****************************************************************************/
+
+union acpi_operand_object {
+ struct acpi_object_common common;
+ struct acpi_object_integer integer;
+ struct acpi_object_string string;
+ struct acpi_object_buffer buffer;
+ struct acpi_object_package package;
+ struct acpi_object_event event;
+ struct acpi_object_method method;
+ struct acpi_object_mutex mutex;
+ struct acpi_object_region region;
+ struct acpi_object_notify_common common_notify;
+ struct acpi_object_device device;
+ struct acpi_object_power_resource power_resource;
+ struct acpi_object_processor processor;
+ struct acpi_object_thermal_zone thermal_zone;
+ struct acpi_object_field_common common_field;
+ struct acpi_object_region_field field;
+ struct acpi_object_buffer_field buffer_field;
+ struct acpi_object_bank_field bank_field;
+ struct acpi_object_index_field index_field;
+ struct acpi_object_notify_handler notify;
+ struct acpi_object_addr_handler address_space;
+ struct acpi_object_reference reference;
+ struct acpi_object_extra extra;
+ struct acpi_object_data data;
+ struct acpi_object_cache_list cache;
+
+ /*
+ * Add namespace node to union in order to simplify code that accepts both
+ * ACPI_OPERAND_OBJECTs and ACPI_NAMESPACE_NODEs. The structures share
+ * a common descriptor_type field in order to differentiate them.
+ */
+ struct acpi_namespace_node node;
+};
+
+/******************************************************************************
+ *
+ * union acpi_descriptor - objects that share a common descriptor identifier
+ *
+ *****************************************************************************/
+
+/* Object descriptor types */
+
+#define ACPI_DESC_TYPE_CACHED 0x01 /* Used only when object is cached */
+#define ACPI_DESC_TYPE_STATE 0x02
+#define ACPI_DESC_TYPE_STATE_UPDATE 0x03
+#define ACPI_DESC_TYPE_STATE_PACKAGE 0x04
+#define ACPI_DESC_TYPE_STATE_CONTROL 0x05
+#define ACPI_DESC_TYPE_STATE_RPSCOPE 0x06
+#define ACPI_DESC_TYPE_STATE_PSCOPE 0x07
+#define ACPI_DESC_TYPE_STATE_WSCOPE 0x08
+#define ACPI_DESC_TYPE_STATE_RESULT 0x09
+#define ACPI_DESC_TYPE_STATE_NOTIFY 0x0A
+#define ACPI_DESC_TYPE_STATE_THREAD 0x0B
+#define ACPI_DESC_TYPE_WALK 0x0C
+#define ACPI_DESC_TYPE_PARSER 0x0D
+#define ACPI_DESC_TYPE_OPERAND 0x0E
+#define ACPI_DESC_TYPE_NAMED 0x0F
+#define ACPI_DESC_TYPE_MAX 0x0F
+
+struct acpi_common_descriptor {
+ void *common_pointer;
+ u8 descriptor_type; /* To differentiate various internal objs */
+};
+
+union acpi_descriptor {
+ struct acpi_common_descriptor common;
+ union acpi_operand_object object;
+ struct acpi_namespace_node node;
+ union acpi_parse_object op;
+};
+
+#pragma pack()
+
+#endif /* _ACOBJECT_H */
diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h
new file mode 100644
index 000000000000..dfdf63327885
--- /dev/null
+++ b/drivers/acpi/acpica/acopcode.h
@@ -0,0 +1,323 @@
+/******************************************************************************
+ *
+ * Name: acopcode.h - AML opcode information for the AML parser and interpreter
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACOPCODE_H__
+#define __ACOPCODE_H__
+
+#define MAX_EXTENDED_OPCODE 0x88
+#define NUM_EXTENDED_OPCODE (MAX_EXTENDED_OPCODE + 1)
+#define MAX_INTERNAL_OPCODE
+#define NUM_INTERNAL_OPCODE (MAX_INTERNAL_OPCODE + 1)
+
+/* Used for non-assigned opcodes */
+
+#define _UNK 0x6B
+
+/*
+ * Reserved ASCII characters. Do not use any of these for
+ * internal opcodes, since they are used to differentiate
+ * name strings from AML opcodes
+ */
+#define _ASC 0x6C
+#define _NAM 0x6C
+#define _PFX 0x6D
+
+/*
+ * All AML opcodes and the parse-time arguments for each. Used by the AML
+ * parser Each list is compressed into a 32-bit number and stored in the
+ * master opcode table (in psopcode.c).
+ */
+#define ARGP_ACCESSFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_ACQUIRE_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_WORDDATA)
+#define ARGP_ADD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_ALIAS_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_NAME)
+#define ARGP_ARG0 ARG_NONE
+#define ARGP_ARG1 ARG_NONE
+#define ARGP_ARG2 ARG_NONE
+#define ARGP_ARG3 ARG_NONE
+#define ARGP_ARG4 ARG_NONE
+#define ARGP_ARG5 ARG_NONE
+#define ARGP_ARG6 ARG_NONE
+#define ARGP_BANK_FIELD_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_TERMARG, ARGP_BYTEDATA, ARGP_FIELDLIST)
+#define ARGP_BIT_AND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_NAND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_NOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_NOT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_OR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_XOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BREAK_OP ARG_NONE
+#define ARGP_BREAK_POINT_OP ARG_NONE
+#define ARGP_BUFFER_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_BYTELIST)
+#define ARGP_BYTE_OP ARGP_LIST1 (ARGP_BYTEDATA)
+#define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME)
+#define ARGP_CONTINUE_OP ARG_NONE
+#define ARGP_COPY_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SIMPLENAME)
+#define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_FIELD_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_QWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_WORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_DEBUG_OP ARG_NONE
+#define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST)
+#define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET)
+#define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA)
+#define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST)
+#define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME)
+#define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG)
+#define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST)
+#define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_FIND_SET_RIGHT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_FROM_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_IF_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST)
+#define ARGP_INCREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_INDEX_FIELD_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_BYTEDATA, ARGP_FIELDLIST)
+#define ARGP_INDEX_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_LAND_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LGREATER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LGREATEREQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LLESS_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LLESSEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LNOT_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_LNOTEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LOAD_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_SUPERNAME)
+#define ARGP_LOAD_TABLE_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LOCAL0 ARG_NONE
+#define ARGP_LOCAL1 ARG_NONE
+#define ARGP_LOCAL2 ARG_NONE
+#define ARGP_LOCAL3 ARG_NONE
+#define ARGP_LOCAL4 ARG_NONE
+#define ARGP_LOCAL5 ARG_NONE
+#define ARGP_LOCAL6 ARG_NONE
+#define ARGP_LOCAL7 ARG_NONE
+#define ARGP_LOR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_MATCH_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_METHOD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMLIST)
+#define ARGP_METHODCALL_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_MID_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_MOD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_MULTIPLY_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_MUTEX_OP ARGP_LIST2 (ARGP_NAME, ARGP_BYTEDATA)
+#define ARGP_NAME_OP ARGP_LIST2 (ARGP_NAME, ARGP_DATAOBJ)
+#define ARGP_NAMEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_NOOP_OP ARG_NONE
+#define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG)
+#define ARGP_ONE_OP ARG_NONE
+#define ARGP_ONES_OP ARG_NONE
+#define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST)
+#define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST)
+#define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST)
+#define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA)
+#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_RESET_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_RETURN_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_REVISION_OP ARG_NONE
+#define ARGP_SCOPE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_TERMLIST)
+#define ARGP_SHIFT_LEFT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_SHIFT_RIGHT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_SIGNAL_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_SIZE_OF_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_SLEEP_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_STALL_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_STATICSTRING_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_STORE_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SUPERNAME)
+#define ARGP_STRING_OP ARGP_LIST1 (ARGP_CHARLIST)
+#define ARGP_SUBTRACT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_THERMAL_ZONE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST)
+#define ARGP_TIMER_OP ARG_NONE
+#define ARGP_TO_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_BUFFER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_DEC_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_HEX_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_INTEGER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TYPE_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_DATAOBJLIST)
+#define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG)
+#define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST)
+#define ARGP_WORD_OP ARGP_LIST1 (ARGP_WORDDATA)
+#define ARGP_ZERO_OP ARG_NONE
+
+/*
+ * All AML opcodes and the runtime arguments for each. Used by the AML
+ * interpreter Each list is compressed into a 32-bit number and stored
+ * in the master opcode table (in psopcode.c).
+ *
+ * (Used by prep_operands procedure and the ASL Compiler)
+ */
+#define ARGI_ACCESSFIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_ACQUIRE_OP ARGI_LIST2 (ARGI_MUTEX, ARGI_INTEGER)
+#define ARGI_ADD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_ALIAS_OP ARGI_INVALID_OPCODE
+#define ARGI_ARG0 ARG_NONE
+#define ARGI_ARG1 ARG_NONE
+#define ARGI_ARG2 ARG_NONE
+#define ARGI_ARG3 ARG_NONE
+#define ARGI_ARG4 ARG_NONE
+#define ARGI_ARG5 ARG_NONE
+#define ARGI_ARG6 ARG_NONE
+#define ARGI_BANK_FIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_BIT_AND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_NAND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_NOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_NOT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_OR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BREAK_OP ARG_NONE
+#define ARGI_BREAK_POINT_OP ARG_NONE
+#define ARGI_BUFFER_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_BYTE_OP ARGI_INVALID_OPCODE
+#define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE
+#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA, ARGI_TARGETREF)
+#define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF)
+#define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF)
+#define ARGI_CONTINUE_OP ARGI_INVALID_OPCODE
+#define ARGI_COPY_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_SIMPLE_TARGET)
+#define ARGI_CREATE_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_CREATE_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_CREATE_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_INTEGER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_CREATE_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING)
+#define ARGI_DEBUG_OP ARG_NONE
+#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_TARGETREF)
+#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING)
+#define ARGI_DEVICE_OP ARGI_INVALID_OPCODE
+#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF)
+#define ARGI_DWORD_OP ARGI_INVALID_OPCODE
+#define ARGI_ELSE_OP ARGI_INVALID_OPCODE
+#define ARGI_EVENT_OP ARGI_INVALID_OPCODE
+#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER)
+#define ARGI_FIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET)
+#define ARGI_IF_OP ARGI_INVALID_OPCODE
+#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_TARGETREF)
+#define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER)
+#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA)
+#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA)
+#define ARGI_LGREATEREQUAL_OP ARGI_INVALID_OPCODE
+#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA)
+#define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE
+#define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE
+#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_BUFFER,ARGI_TARGETREF)
+#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_ANYTYPE)
+#define ARGI_LOCAL0 ARG_NONE
+#define ARGI_LOCAL1 ARG_NONE
+#define ARGI_LOCAL2 ARG_NONE
+#define ARGI_LOCAL3 ARG_NONE
+#define ARGI_LOCAL4 ARG_NONE
+#define ARGI_LOCAL5 ARG_NONE
+#define ARGI_LOCAL6 ARG_NONE
+#define ARGI_LOCAL7 ARG_NONE
+#define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER)
+#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_COMPUTEDATA, ARGI_INTEGER,ARGI_COMPUTEDATA,ARGI_INTEGER)
+#define ARGI_METHOD_OP ARGI_INVALID_OPCODE
+#define ARGI_METHODCALL_OP ARGI_INVALID_OPCODE
+#define ARGI_MID_OP ARGI_LIST4 (ARGI_BUFFER_OR_STRING,ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_MOD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_MULTIPLY_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_MUTEX_OP ARGI_INVALID_OPCODE
+#define ARGI_NAME_OP ARGI_INVALID_OPCODE
+#define ARGI_NAMEDFIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_NAMEPATH_OP ARGI_INVALID_OPCODE
+#define ARGI_NOOP_OP ARG_NONE
+#define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER)
+#define ARGI_ONE_OP ARG_NONE
+#define ARGI_ONES_OP ARG_NONE
+#define ARGI_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_POWER_RES_OP ARGI_INVALID_OPCODE
+#define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE
+#define ARGI_QWORD_OP ARGI_INVALID_OPCODE
+#define ARGI_REF_OF_OP ARGI_LIST1 (ARGI_OBJECT_REF)
+#define ARGI_REGION_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER)
+#define ARGI_RELEASE_OP ARGI_LIST1 (ARGI_MUTEX)
+#define ARGI_RESERVEDFIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_RESET_OP ARGI_LIST1 (ARGI_EVENT)
+#define ARGI_RETURN_OP ARGI_INVALID_OPCODE
+#define ARGI_REVISION_OP ARG_NONE
+#define ARGI_SCOPE_OP ARGI_INVALID_OPCODE
+#define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_SIGNAL_OP ARGI_LIST1 (ARGI_EVENT)
+#define ARGI_SIZE_OF_OP ARGI_LIST1 (ARGI_DATAOBJECT)
+#define ARGI_SLEEP_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_STALL_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_STATICSTRING_OP ARGI_INVALID_OPCODE
+#define ARGI_STORE_OP ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_TARGETREF)
+#define ARGI_STRING_OP ARGI_INVALID_OPCODE
+#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE
+#define ARGI_TIMER_OP ARG_NONE
+#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET)
+#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
+#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
+#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
+#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
+#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET)
+#define ARGI_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE)
+#define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE)
+#define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER)
+#define ARGI_WHILE_OP ARGI_INVALID_OPCODE
+#define ARGI_WORD_OP ARGI_INVALID_OPCODE
+#define ARGI_ZERO_OP ARG_NONE
+
+#endif /* __ACOPCODE_H__ */
diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h
new file mode 100644
index 000000000000..23ee0fbf5619
--- /dev/null
+++ b/drivers/acpi/acpica/acparser.h
@@ -0,0 +1,234 @@
+/******************************************************************************
+ *
+ * Module Name: acparser.h - AML Parser subcomponent prototypes and defines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACPARSER_H__
+#define __ACPARSER_H__
+
+#define OP_HAS_RETURN_VALUE 1
+
+/* Variable number of arguments. This field must be 32 bits */
+
+#define ACPI_VAR_ARGS ACPI_UINT32_MAX
+
+#define ACPI_PARSE_DELETE_TREE 0x0001
+#define ACPI_PARSE_NO_TREE_DELETE 0x0000
+#define ACPI_PARSE_TREE_MASK 0x0001
+
+#define ACPI_PARSE_LOAD_PASS1 0x0010
+#define ACPI_PARSE_LOAD_PASS2 0x0020
+#define ACPI_PARSE_EXECUTE 0x0030
+#define ACPI_PARSE_MODE_MASK 0x0030
+
+#define ACPI_PARSE_DEFERRED_OP 0x0100
+#define ACPI_PARSE_DISASSEMBLE 0x0200
+
+/******************************************************************************
+ *
+ * Parser interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * psxface - Parser external interfaces
+ */
+acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info);
+
+/*
+ * psargs - Parse AML opcode arguments
+ */
+u8 *acpi_ps_get_next_package_end(struct acpi_parse_state *parser_state);
+
+char *acpi_ps_get_next_namestring(struct acpi_parse_state *parser_state);
+
+void
+acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state,
+ u32 arg_type, union acpi_parse_object *arg);
+
+acpi_status
+acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
+ struct acpi_parse_state *parser_state,
+ union acpi_parse_object *arg, u8 method_call);
+
+acpi_status
+acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
+ struct acpi_parse_state *parser_state,
+ u32 arg_type, union acpi_parse_object **return_arg);
+
+/*
+ * psfind
+ */
+union acpi_parse_object *acpi_ps_find_name(union acpi_parse_object *scope,
+ u32 name, u32 opcode);
+
+union acpi_parse_object *acpi_ps_get_parent(union acpi_parse_object *op);
+
+/*
+ * psopcode - AML Opcode information
+ */
+const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode);
+
+char *acpi_ps_get_opcode_name(u16 opcode);
+
+u8 acpi_ps_get_argument_count(u32 op_type);
+
+/*
+ * psparse - top level parsing routines
+ */
+acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state);
+
+u32 acpi_ps_get_opcode_size(u32 opcode);
+
+u16 acpi_ps_peek_opcode(struct acpi_parse_state *state);
+
+acpi_status
+acpi_ps_complete_this_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
+acpi_status
+acpi_ps_next_parse_state(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ acpi_status callback_status);
+
+/*
+ * psloop - main parse loop
+ */
+acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state);
+
+/*
+ * psscope - Scope stack management routines
+ */
+acpi_status
+acpi_ps_init_scope(struct acpi_parse_state *parser_state,
+ union acpi_parse_object *root);
+
+union acpi_parse_object *acpi_ps_get_parent_scope(struct acpi_parse_state
+ *state);
+
+u8 acpi_ps_has_completed_scope(struct acpi_parse_state *parser_state);
+
+void
+acpi_ps_pop_scope(struct acpi_parse_state *parser_state,
+ union acpi_parse_object **op,
+ u32 * arg_list, u32 * arg_count);
+
+acpi_status
+acpi_ps_push_scope(struct acpi_parse_state *parser_state,
+ union acpi_parse_object *op,
+ u32 remaining_args, u32 arg_count);
+
+void acpi_ps_cleanup_scope(struct acpi_parse_state *state);
+
+/*
+ * pstree - parse tree manipulation routines
+ */
+void
+acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg);
+
+union acpi_parse_object *acpi_ps_find(union acpi_parse_object *scope,
+ char *path, u16 opcode, u32 create);
+
+union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn);
+
+#ifdef ACPI_FUTURE_USAGE
+union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin,
+ union acpi_parse_object *op);
+#endif /* ACPI_FUTURE_USAGE */
+
+/*
+ * pswalk - parse tree walk routines
+ */
+acpi_status
+acpi_ps_walk_parsed_aml(union acpi_parse_object *start_op,
+ union acpi_parse_object *end_op,
+ union acpi_operand_object *mth_desc,
+ struct acpi_namespace_node *start_node,
+ union acpi_operand_object **params,
+ union acpi_operand_object **caller_return_desc,
+ acpi_owner_id owner_id,
+ acpi_parse_downwards descending_callback,
+ acpi_parse_upwards ascending_callback);
+
+acpi_status
+acpi_ps_get_next_walk_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ acpi_parse_upwards ascending_callback);
+
+acpi_status acpi_ps_delete_completed_op(struct acpi_walk_state *walk_state);
+
+void acpi_ps_delete_parse_tree(union acpi_parse_object *root);
+
+/*
+ * psutils - parser utilities
+ */
+union acpi_parse_object *acpi_ps_create_scope_op(void);
+
+void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode);
+
+union acpi_parse_object *acpi_ps_alloc_op(u16 opcode);
+
+void acpi_ps_free_op(union acpi_parse_object *op);
+
+u8 acpi_ps_is_leading_char(u32 c);
+
+u8 acpi_ps_is_prefix_char(u32 c);
+
+#ifdef ACPI_FUTURE_USAGE
+u32 acpi_ps_get_name(union acpi_parse_object *op);
+#endif /* ACPI_FUTURE_USAGE */
+
+void acpi_ps_set_name(union acpi_parse_object *op, u32 name);
+
+/*
+ * psdump - display parser tree
+ */
+u32
+acpi_ps_sprint_path(char *buffer_start,
+ u32 buffer_size, union acpi_parse_object *op);
+
+u32
+acpi_ps_sprint_op(char *buffer_start,
+ u32 buffer_size, union acpi_parse_object *op);
+
+void acpi_ps_show(union acpi_parse_object *op);
+
+#endif /* __ACPARSER_H__ */
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
new file mode 100644
index 000000000000..16a9ca9a66e4
--- /dev/null
+++ b/drivers/acpi/acpica/acpredef.h
@@ -0,0 +1,371 @@
+/******************************************************************************
+ *
+ * Name: acpredef - Information table for ACPI predefined methods and objects
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACPREDEF_H__
+#define __ACPREDEF_H__
+
+/******************************************************************************
+ *
+ * Return Package types
+ *
+ * 1) PTYPE1 packages do not contain sub-packages.
+ *
+ * ACPI_PTYPE1_FIXED: Fixed length, 1 or 2 object types:
+ * object type
+ * count
+ * object type
+ * count
+ *
+ * ACPI_PTYPE1_VAR: Variable length:
+ * object type (Int/Buf/Ref)
+ *
+ * ACPI_PTYPE1_OPTION: Package has some required and some optional elements:
+ * Used for _PRW
+ *
+ *
+ * 2) PTYPE2 packages contain a variable number of sub-packages. Each of the
+ * different types describe the contents of each of the sub-packages.
+ *
+ * ACPI_PTYPE2: Each subpackage contains 1 or 2 object types:
+ * object type
+ * count
+ * object type
+ * count
+ *
+ * ACPI_PTYPE2_COUNT: Each subpackage has a count as first element:
+ * object type
+ *
+ * ACPI_PTYPE2_PKG_COUNT: Count of subpackages at start, 1 or 2 object types:
+ * object type
+ * count
+ * object type
+ * count
+ *
+ * ACPI_PTYPE2_FIXED: Each subpackage is of fixed length:
+ * Used for _PRT
+ *
+ * ACPI_PTYPE2_MIN: Each subpackage has a variable but minimum length
+ * Used for _HPX
+ *
+ *****************************************************************************/
+
+enum acpi_return_package_types {
+ ACPI_PTYPE1_FIXED = 1,
+ ACPI_PTYPE1_VAR = 2,
+ ACPI_PTYPE1_OPTION = 3,
+ ACPI_PTYPE2 = 4,
+ ACPI_PTYPE2_COUNT = 5,
+ ACPI_PTYPE2_PKG_COUNT = 6,
+ ACPI_PTYPE2_FIXED = 7,
+ ACPI_PTYPE2_MIN = 8
+};
+
+/*
+ * Predefined method/object information table.
+ *
+ * These are the names that can actually be evaluated via acpi_evaluate_object.
+ * Not present in this table are the following:
+ *
+ * 1) Predefined/Reserved names that are never evaluated via acpi_evaluate_object:
+ * _Lxx and _Exx GPE methods
+ * _Qxx EC methods
+ * _T_x compiler temporary variables
+ *
+ * 2) Predefined names that never actually exist within the AML code:
+ * Predefined resource descriptor field names
+ *
+ * 3) Predefined names that are implemented within ACPICA:
+ * _OSI
+ *
+ * 4) Some predefined names that are not documented within the ACPI spec.
+ * _WDG, _WED
+ *
+ * The main entries in the table each contain the following items:
+ *
+ * Name - The ACPI reserved name
+ * param_count - Number of arguments to the method
+ * expected_btypes - Allowed type(s) for the return value.
+ * 0 means that no return value is expected.
+ *
+ * For methods that return packages, the next entry in the table contains
+ * information about the expected structure of the package. This information
+ * is saved here (rather than in a separate table) in order to minimize the
+ * overall size of the stored data.
+ */
+static const union acpi_predefined_info predefined_names[] = {
+ {.info = {"_AC0", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_AC1", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_AC2", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_AC3", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_AC4", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_AC5", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_AC6", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_AC7", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_AC8", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_AC9", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_ADR", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_AL0", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_AL1", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_AL2", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_AL3", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_AL4", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_AL5", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_AL6", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_AL7", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_AL8", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_AL9", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_ALC", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_ALI", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_ALP", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_ALR", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 2, 0, 0, 0}}, /* variable (Pkgs) each 2 (Ints) */
+ {.info = {"_ALT", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_BBN", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_BCL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Ints) */
+ {.info = {"_BCM", 1, 0}},
+ {.info = {"_BDN", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_BFS", 1, 0}},
+ {.info = {"_BIF", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER,
+ 9,
+ ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER, 4, 0}}, /* fixed (9 Int),(4 Str) */
+ {.info = {"_BLT", 3, 0}},
+ {.info = {"_BMC", 1, 0}},
+ {.info = {"_BMD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* fixed (5 Int) */
+ {.info = {"_BQC", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_BST", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0}}, /* fixed (4 Int) */
+ {.info = {"_BTM", 1, ACPI_RTYPE_INTEGER}},
+ {.info = {"_BTP", 1, 0}},
+ {.info = {"_CBA", 0, ACPI_RTYPE_INTEGER}}, /* see PCI firmware spec 3.0 */
+ {.info = {"_CID", 0,
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE}},
+ {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0, 0, 0, 0}}, /* variable (Ints/Strs) */
+ {.info = {"_CRS", 0, ACPI_RTYPE_BUFFER}},
+ {.info = {"_CRT", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_CSD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (1 Int(n), n-1 Int) */
+ {.info = {"_CST", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_PKG_COUNT,
+ ACPI_RTYPE_BUFFER, 1,
+ ACPI_RTYPE_INTEGER, 3, 0}}, /* variable (1 Int(n), n Pkg (1 Buf/3 Int) */
+ {.info = {"_DCK", 1, ACPI_RTYPE_INTEGER}},
+ {.info = {"_DCS", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_DDC", 1, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER}},
+ {.info = {"_DDN", 0, ACPI_RTYPE_STRING}},
+ {.info = {"_DGS", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_DIS", 0, 0}},
+ {.info = {"_DMA", 0, ACPI_RTYPE_BUFFER}},
+ {.info = {"_DOD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Ints) */
+ {.info = {"_DOS", 1, 0}},
+ {.info = {"_DSM", 4, ACPI_RTYPE_ALL}}, /* Must return a type, but it can be of any type */
+ {.info = {"_DSS", 1, 0}},
+ {.info = {"_DSW", 3, 0}},
+ {.info = {"_EC_", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_EDL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_EJ0", 1, 0}},
+ {.info = {"_EJ1", 1, 0}},
+ {.info = {"_EJ2", 1, 0}},
+ {.info = {"_EJ3", 1, 0}},
+ {.info = {"_EJ4", 1, 0}},
+ {.info = {"_EJD", 0, ACPI_RTYPE_STRING}},
+ {.info = {"_FDE", 0, ACPI_RTYPE_BUFFER}},
+ {.info = {"_FDI", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, 0, 0, 0}}, /* fixed (16 Int) */
+ {.info = {"_FDM", 1, 0}},
+ {.info = {"_FIX", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Ints) */
+ {.info = {"_GLK", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_GPD", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_GPE", 0, ACPI_RTYPE_INTEGER}}, /* _GPE method, not _GPE scope */
+ {.info = {"_GSB", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_GTF", 0, ACPI_RTYPE_BUFFER}},
+ {.info = {"_GTM", 0, ACPI_RTYPE_BUFFER}},
+ {.info = {"_GTS", 1, 0}},
+ {.info = {"_HID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}},
+ {.info = {"_HOT", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_HPP", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0}}, /* fixed (4 Int) */
+
+ /*
+ * For _HPX, a single package is returned, containing a variable number of sub-packages.
+ * Each sub-package contains a PCI record setting. There are several different type of
+ * record settings, of different lengths, but all elements of all settings are Integers.
+ */
+ {.info = {"_HPX", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* variable (Pkgs) each (var Ints) */
+ {.info = {"_IFT", 0, ACPI_RTYPE_INTEGER}}, /* see IPMI spec */
+ {.info = {"_INI", 0, 0}},
+ {.info = {"_IRC", 0, 0}},
+ {.info = {"_LCK", 1, 0}},
+ {.info = {"_LID", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_MAT", 0, ACPI_RTYPE_BUFFER}},
+ {.info = {"_MLS", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_STRING, 2, 0, 0, 0}}, /* variable (Pkgs) each (2 Str) */
+ {.info = {"_MSG", 1, 0}},
+ {.info = {"_OFF", 0, 0}},
+ {.info = {"_ON_", 0, 0}},
+ {.info = {"_OS_", 0, ACPI_RTYPE_STRING}},
+ {.info = {"_OSC", 4, ACPI_RTYPE_BUFFER}},
+ {.info = {"_OST", 3, 0}},
+ {.info = {"_PCL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_PCT", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2, 0, 0, 0}}, /* fixed (2 Buf) */
+ {.info = {"_PDC", 1, 0}},
+ {.info = {"_PIC", 1, 0}},
+ {.info = {"_PLD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_BUFFER, 0, 0, 0, 0}}, /* variable (Bufs) */
+ {.info = {"_PPC", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_PPE", 0, ACPI_RTYPE_INTEGER}}, /* see dig64 spec */
+ {.info = {"_PR0", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_PR1", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_PR2", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_PRS", 0, ACPI_RTYPE_BUFFER}},
+
+ /*
+ * For _PRT, many BIOSs reverse the 2nd and 3rd Package elements. This bug is so prevalent that there
+ * is code in the ACPICA Resource Manager to detect this and switch them back. For now, do not allow
+ * and issue a warning. To allow this and eliminate the warning, add the ACPI_RTYPE_REFERENCE
+ * type to the 2nd element (index 1) in the statement below.
+ */
+ {.info = {"_PRT", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_FIXED, 4,
+ ACPI_RTYPE_INTEGER,
+ ACPI_RTYPE_INTEGER,
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_REFERENCE, ACPI_RTYPE_INTEGER}}, /* variable (Pkgs) each (4): Int,Int,Int/Ref,Int */
+
+ {.info = {"_PRW", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_OPTION, 2,
+ ACPI_RTYPE_INTEGER |
+ ACPI_RTYPE_PACKAGE,
+ ACPI_RTYPE_INTEGER, ACPI_RTYPE_REFERENCE, 0}}, /* variable (Pkgs) each: Pkg/Int,Int,[variable Refs] (Pkg is Ref/Int) */
+
+ {.info = {"_PS0", 0, 0}},
+ {.info = {"_PS1", 0, 0}},
+ {.info = {"_PS2", 0, 0}},
+ {.info = {"_PS3", 0, 0}},
+ {.info = {"_PSC", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_PSD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Pkgs) each (5 Int) with count */
+ {.info = {"_PSL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_PSR", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_PSS", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 6, 0, 0, 0}}, /* variable (Pkgs) each (6 Int) */
+ {.info = {"_PSV", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_PSW", 1, 0}},
+ {.info = {"_PTC", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2, 0, 0, 0}}, /* fixed (2 Buf) */
+ {.info = {"_PTS", 1, 0}},
+ {.info = {"_PXM", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_REG", 2, 0}},
+ {.info = {"_REV", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_RMV", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_ROM", 2, ACPI_RTYPE_BUFFER}},
+ {.info = {"_RTV", 0, ACPI_RTYPE_INTEGER}},
+
+ /*
+ * For _S0_ through _S5_, the ACPI spec defines a return Package containing 1 Integer,
+ * but most DSDTs have it wrong - 2,3, or 4 integers. Allow this by making the objects "variable length",
+ * but all elements must be Integers.
+ */
+ {.info = {"_S0_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */
+ {.info = {"_S1_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */
+ {.info = {"_S2_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */
+ {.info = {"_S3_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */
+ {.info = {"_S4_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */
+ {.info = {"_S5_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */
+
+ {.info = {"_S1D", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_S2D", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_S3D", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_S4D", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_S0W", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_S1W", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_S2W", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_S3W", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_S4W", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_SBS", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_SCP", 0x13, 0}}, /* Acpi 1.0 allowed 1 arg. Acpi 3.0 expanded to 3 args. Allow both. */
+ /* Note: the 3-arg definition may be removed for ACPI 4.0 */
+ {.info = {"_SDD", 1, 0}},
+ {.info = {"_SEG", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_SLI", 0, ACPI_RTYPE_BUFFER}},
+ {.info = {"_SPD", 1, ACPI_RTYPE_INTEGER}},
+ {.info = {"_SRS", 1, 0}},
+ {.info = {"_SRV", 0, ACPI_RTYPE_INTEGER}}, /* see IPMI spec */
+ {.info = {"_SST", 1, 0}},
+ {.info = {"_STA", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_STM", 3, 0}},
+ {.info = {"_STR", 0, ACPI_RTYPE_BUFFER}},
+ {.info = {"_SUN", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_SWS", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_TC1", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_TC2", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_TMP", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_TPC", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_TPT", 1, 0}},
+ {.info = {"_TRT", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_REFERENCE, 2,
+ ACPI_RTYPE_INTEGER, 6, 0}}, /* variable (Pkgs) each 2_ref/6_int */
+ {.info = {"_TSD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* variable (Pkgs) each 5_int with count */
+ {.info = {"_TSP", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_TSS", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* variable (Pkgs) each 5_int */
+ {.info = {"_TST", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_TTS", 1, 0}},
+ {.info = {"_TZD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */
+ {.info = {"_TZM", 0, ACPI_RTYPE_REFERENCE}},
+ {.info = {"_TZP", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_UID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}},
+ {.info = {"_UPC", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0}}, /* fixed (4 Int) */
+ {.info = {"_UPD", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_UPP", 0, ACPI_RTYPE_INTEGER}},
+ {.info = {"_VPO", 0, ACPI_RTYPE_INTEGER}},
+
+ /* Acpi 1.0 defined _WAK with no return value. Later, it was changed to return a package */
+
+ {.info = {"_WAK", 1, ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE}},
+ {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0}}, /* fixed (2 Int), but is optional */
+ {.ret_info = {0, 0, 0, 0, 0, 0}} /* Table terminator */
+};
+
+#if 0
+ /* Not implemented */
+
+{
+"_WDG", 0, ACPI_RTYPE_BUFFER}, /* MS Extension */
+
+{
+"_WED", 1, ACPI_RTYPE_PACKAGE}, /* MS Extension */
+
+ /* This is an internally implemented control method, no need to check */
+{
+"_OSI", 1, ACPI_RTYPE_INTEGER},
+
+ /* TBD: */
+ _PRT - currently ignore reversed entries.attempt to fix here ?
+ think about code that attempts to fix package elements like _BIF, etc.
+#endif
+#endif
diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h
new file mode 100644
index 000000000000..eef5bd7a59fa
--- /dev/null
+++ b/drivers/acpi/acpica/acresrc.h
@@ -0,0 +1,336 @@
+/******************************************************************************
+ *
+ * Name: acresrc.h - Resource Manager function prototypes
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACRESRC_H__
+#define __ACRESRC_H__
+
+/* Need the AML resource descriptor structs */
+
+#include "amlresrc.h"
+
+/*
+ * If possible, pack the following structures to byte alignment, since we
+ * don't care about performance for debug output. Two cases where we cannot
+ * pack the structures:
+ *
+ * 1) Hardware does not support misaligned memory transfers
+ * 2) Compiler does not support pointers within packed structures
+ */
+#if (!defined(ACPI_MISALIGNMENT_NOT_SUPPORTED) && !defined(ACPI_PACKED_POINTERS_NOT_SUPPORTED))
+#pragma pack(1)
+#endif
+
+/*
+ * Individual entry for the resource conversion tables
+ */
+typedef const struct acpi_rsconvert_info {
+ u8 opcode;
+ u8 resource_offset;
+ u8 aml_offset;
+ u8 value;
+
+} acpi_rsconvert_info;
+
+/* Resource conversion opcodes */
+
+#define ACPI_RSC_INITGET 0
+#define ACPI_RSC_INITSET 1
+#define ACPI_RSC_FLAGINIT 2
+#define ACPI_RSC_1BITFLAG 3
+#define ACPI_RSC_2BITFLAG 4
+#define ACPI_RSC_COUNT 5
+#define ACPI_RSC_COUNT16 6
+#define ACPI_RSC_LENGTH 7
+#define ACPI_RSC_MOVE8 8
+#define ACPI_RSC_MOVE16 9
+#define ACPI_RSC_MOVE32 10
+#define ACPI_RSC_MOVE64 11
+#define ACPI_RSC_SET8 12
+#define ACPI_RSC_DATA8 13
+#define ACPI_RSC_ADDRESS 14
+#define ACPI_RSC_SOURCE 15
+#define ACPI_RSC_SOURCEX 16
+#define ACPI_RSC_BITMASK 17
+#define ACPI_RSC_BITMASK16 18
+#define ACPI_RSC_EXIT_NE 19
+#define ACPI_RSC_EXIT_LE 20
+#define ACPI_RSC_EXIT_EQ 21
+
+/* Resource Conversion sub-opcodes */
+
+#define ACPI_RSC_COMPARE_AML_LENGTH 0
+#define ACPI_RSC_COMPARE_VALUE 1
+
+#define ACPI_RSC_TABLE_SIZE(d) (sizeof (d) / sizeof (struct acpi_rsconvert_info))
+
+#define ACPI_RS_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_resource,f)
+#define AML_OFFSET(f) (u8) ACPI_OFFSET (union aml_resource,f)
+
+typedef const struct acpi_rsdump_info {
+ u8 opcode;
+ u8 offset;
+ char *name;
+ const char **pointer;
+
+} acpi_rsdump_info;
+
+/* Values for the Opcode field above */
+
+#define ACPI_RSD_TITLE 0
+#define ACPI_RSD_LITERAL 1
+#define ACPI_RSD_STRING 2
+#define ACPI_RSD_UINT8 3
+#define ACPI_RSD_UINT16 4
+#define ACPI_RSD_UINT32 5
+#define ACPI_RSD_UINT64 6
+#define ACPI_RSD_1BITFLAG 7
+#define ACPI_RSD_2BITFLAG 8
+#define ACPI_RSD_SHORTLIST 9
+#define ACPI_RSD_LONGLIST 10
+#define ACPI_RSD_DWORDLIST 11
+#define ACPI_RSD_ADDRESS 12
+#define ACPI_RSD_SOURCE 13
+
+/* restore default alignment */
+
+#pragma pack()
+
+/* Resource tables indexed by internal resource type */
+
+extern const u8 acpi_gbl_aml_resource_sizes[];
+extern struct acpi_rsconvert_info *acpi_gbl_set_resource_dispatch[];
+
+/* Resource tables indexed by raw AML resource descriptor type */
+
+extern const u8 acpi_gbl_resource_struct_sizes[];
+extern struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[];
+
+struct acpi_vendor_walk_info {
+ struct acpi_vendor_uuid *uuid;
+ struct acpi_buffer *buffer;
+ acpi_status status;
+};
+
+/*
+ * rscreate
+ */
+acpi_status
+acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer,
+ struct acpi_buffer *output_buffer);
+
+acpi_status
+acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer,
+ struct acpi_buffer *output_buffer);
+
+acpi_status
+acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
+ struct acpi_buffer *output_buffer);
+
+/*
+ * rsutils
+ */
+
+acpi_status
+acpi_rs_get_prt_method_data(struct acpi_namespace_node *node,
+ struct acpi_buffer *ret_buffer);
+
+acpi_status
+acpi_rs_get_crs_method_data(struct acpi_namespace_node *node,
+ struct acpi_buffer *ret_buffer);
+
+acpi_status
+acpi_rs_get_prs_method_data(struct acpi_namespace_node *node,
+ struct acpi_buffer *ret_buffer);
+
+acpi_status
+acpi_rs_get_method_data(acpi_handle handle,
+ char *path, struct acpi_buffer *ret_buffer);
+
+acpi_status
+acpi_rs_set_srs_method_data(struct acpi_namespace_node *node,
+ struct acpi_buffer *ret_buffer);
+
+/*
+ * rscalc
+ */
+acpi_status
+acpi_rs_get_list_length(u8 * aml_buffer,
+ u32 aml_buffer_length, acpi_size * size_needed);
+
+acpi_status
+acpi_rs_get_aml_length(struct acpi_resource *linked_list_buffer,
+ acpi_size * size_needed);
+
+acpi_status
+acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
+ acpi_size * buffer_size_needed);
+
+acpi_status
+acpi_rs_convert_aml_to_resources(u8 * aml,
+ u32 length,
+ u32 offset, u8 resource_index, void **context);
+
+acpi_status
+acpi_rs_convert_resources_to_aml(struct acpi_resource *resource,
+ acpi_size aml_size_needed, u8 * output_buffer);
+
+/*
+ * rsaddr
+ */
+void
+acpi_rs_set_address_common(union aml_resource *aml,
+ struct acpi_resource *resource);
+
+u8
+acpi_rs_get_address_common(struct acpi_resource *resource,
+ union aml_resource *aml);
+
+/*
+ * rsmisc
+ */
+acpi_status
+acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
+ union aml_resource *aml,
+ struct acpi_rsconvert_info *info);
+
+acpi_status
+acpi_rs_convert_resource_to_aml(struct acpi_resource *resource,
+ union aml_resource *aml,
+ struct acpi_rsconvert_info *info);
+
+/*
+ * rsutils
+ */
+void
+acpi_rs_move_data(void *destination,
+ void *source, u16 item_count, u8 move_type);
+
+u8 acpi_rs_decode_bitmask(u16 mask, u8 * list);
+
+u16 acpi_rs_encode_bitmask(u8 * list, u8 count);
+
+acpi_rs_length
+acpi_rs_get_resource_source(acpi_rs_length resource_length,
+ acpi_rs_length minimum_length,
+ struct acpi_resource_source *resource_source,
+ union aml_resource *aml, char *string_ptr);
+
+acpi_rsdesc_size
+acpi_rs_set_resource_source(union aml_resource *aml,
+ acpi_rs_length minimum_length,
+ struct acpi_resource_source *resource_source);
+
+void
+acpi_rs_set_resource_header(u8 descriptor_type,
+ acpi_rsdesc_size total_length,
+ union aml_resource *aml);
+
+void
+acpi_rs_set_resource_length(acpi_rsdesc_size total_length,
+ union aml_resource *aml);
+
+/*
+ * rsdump
+ */
+void acpi_rs_dump_resource_list(struct acpi_resource *resource);
+
+void acpi_rs_dump_irq_list(u8 * route_table);
+
+/*
+ * Resource conversion tables
+ */
+extern struct acpi_rsconvert_info acpi_rs_convert_dma[];
+extern struct acpi_rsconvert_info acpi_rs_convert_end_dpf[];
+extern struct acpi_rsconvert_info acpi_rs_convert_io[];
+extern struct acpi_rsconvert_info acpi_rs_convert_fixed_io[];
+extern struct acpi_rsconvert_info acpi_rs_convert_end_tag[];
+extern struct acpi_rsconvert_info acpi_rs_convert_memory24[];
+extern struct acpi_rsconvert_info acpi_rs_convert_generic_reg[];
+extern struct acpi_rsconvert_info acpi_rs_convert_memory32[];
+extern struct acpi_rsconvert_info acpi_rs_convert_fixed_memory32[];
+extern struct acpi_rsconvert_info acpi_rs_convert_address32[];
+extern struct acpi_rsconvert_info acpi_rs_convert_address16[];
+extern struct acpi_rsconvert_info acpi_rs_convert_ext_irq[];
+extern struct acpi_rsconvert_info acpi_rs_convert_address64[];
+extern struct acpi_rsconvert_info acpi_rs_convert_ext_address64[];
+
+/* These resources require separate get/set tables */
+
+extern struct acpi_rsconvert_info acpi_rs_get_irq[];
+extern struct acpi_rsconvert_info acpi_rs_get_start_dpf[];
+extern struct acpi_rsconvert_info acpi_rs_get_vendor_small[];
+extern struct acpi_rsconvert_info acpi_rs_get_vendor_large[];
+
+extern struct acpi_rsconvert_info acpi_rs_set_irq[];
+extern struct acpi_rsconvert_info acpi_rs_set_start_dpf[];
+extern struct acpi_rsconvert_info acpi_rs_set_vendor[];
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+/*
+ * rsinfo
+ */
+extern struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[];
+
+/*
+ * rsdump
+ */
+extern struct acpi_rsdump_info acpi_rs_dump_irq[];
+extern struct acpi_rsdump_info acpi_rs_dump_dma[];
+extern struct acpi_rsdump_info acpi_rs_dump_start_dpf[];
+extern struct acpi_rsdump_info acpi_rs_dump_end_dpf[];
+extern struct acpi_rsdump_info acpi_rs_dump_io[];
+extern struct acpi_rsdump_info acpi_rs_dump_fixed_io[];
+extern struct acpi_rsdump_info acpi_rs_dump_vendor[];
+extern struct acpi_rsdump_info acpi_rs_dump_end_tag[];
+extern struct acpi_rsdump_info acpi_rs_dump_memory24[];
+extern struct acpi_rsdump_info acpi_rs_dump_memory32[];
+extern struct acpi_rsdump_info acpi_rs_dump_fixed_memory32[];
+extern struct acpi_rsdump_info acpi_rs_dump_address16[];
+extern struct acpi_rsdump_info acpi_rs_dump_address32[];
+extern struct acpi_rsdump_info acpi_rs_dump_address64[];
+extern struct acpi_rsdump_info acpi_rs_dump_ext_address64[];
+extern struct acpi_rsdump_info acpi_rs_dump_ext_irq[];
+extern struct acpi_rsdump_info acpi_rs_dump_generic_reg[];
+#endif
+
+#endif /* __ACRESRC_H__ */
diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h
new file mode 100644
index 000000000000..7980a26bad35
--- /dev/null
+++ b/drivers/acpi/acpica/acstruct.h
@@ -0,0 +1,228 @@
+/******************************************************************************
+ *
+ * Name: acstruct.h - Internal structs
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACSTRUCT_H__
+#define __ACSTRUCT_H__
+
+/* acpisrc:struct_defs -- for acpisrc conversion */
+
+/*****************************************************************************
+ *
+ * Tree walking typedefs and structs
+ *
+ ****************************************************************************/
+
+/*
+ * Walk state - current state of a parse tree walk. Used for both a leisurely
+ * stroll through the tree (for whatever reason), and for control method
+ * execution.
+ */
+#define ACPI_NEXT_OP_DOWNWARD 1
+#define ACPI_NEXT_OP_UPWARD 2
+
+/*
+ * Groups of definitions for walk_type used for different implementations of
+ * walkers (never simultaneously) - flags for interpreter:
+ */
+#define ACPI_WALK_NON_METHOD 0
+#define ACPI_WALK_METHOD 0x01
+#define ACPI_WALK_METHOD_RESTART 0x02
+
+/* Flags for i_aSL compiler only */
+
+#define ACPI_WALK_CONST_REQUIRED 0x10
+#define ACPI_WALK_CONST_OPTIONAL 0x20
+
+struct acpi_walk_state {
+ struct acpi_walk_state *next; /* Next walk_state in list */
+ u8 descriptor_type; /* To differentiate various internal objs */
+ u8 walk_type;
+ u16 opcode; /* Current AML opcode */
+ u8 next_op_info; /* Info about next_op */
+ u8 num_operands; /* Stack pointer for Operands[] array */
+ u8 operand_index; /* Index into operand stack, to be used by acpi_ds_obj_stack_push */
+ acpi_owner_id owner_id; /* Owner of objects created during the walk */
+ u8 last_predicate; /* Result of last predicate */
+ u8 current_result;
+ u8 return_used;
+ u8 scope_depth;
+ u8 pass_number; /* Parse pass during table load */
+ u8 result_size; /* Total elements for the result stack */
+ u8 result_count; /* Current number of occupied elements of result stack */
+ u32 aml_offset;
+ u32 arg_types;
+ u32 method_breakpoint; /* For single stepping */
+ u32 user_breakpoint; /* User AML breakpoint */
+ u32 parse_flags;
+
+ struct acpi_parse_state parser_state; /* Current state of parser */
+ u32 prev_arg_types;
+ u32 arg_count; /* push for fixed or var args */
+
+ struct acpi_namespace_node arguments[ACPI_METHOD_NUM_ARGS]; /* Control method arguments */
+ struct acpi_namespace_node local_variables[ACPI_METHOD_NUM_LOCALS]; /* Control method locals */
+ union acpi_operand_object *operands[ACPI_OBJ_NUM_OPERANDS + 1]; /* Operands passed to the interpreter (+1 for NULL terminator) */
+ union acpi_operand_object **params;
+
+ u8 *aml_last_while;
+ union acpi_operand_object **caller_return_desc;
+ union acpi_generic_state *control_state; /* List of control states (nested IFs) */
+ struct acpi_namespace_node *deferred_node; /* Used when executing deferred opcodes */
+ union acpi_operand_object *implicit_return_obj;
+ struct acpi_namespace_node *method_call_node; /* Called method Node */
+ union acpi_parse_object *method_call_op; /* method_call Op if running a method */
+ union acpi_operand_object *method_desc; /* Method descriptor if running a method */
+ struct acpi_namespace_node *method_node; /* Method node if running a method. */
+ union acpi_parse_object *op; /* Current parser op */
+ const struct acpi_opcode_info *op_info; /* Info on current opcode */
+ union acpi_parse_object *origin; /* Start of walk [Obsolete] */
+ union acpi_operand_object *result_obj;
+ union acpi_generic_state *results; /* Stack of accumulated results */
+ union acpi_operand_object *return_desc; /* Return object, if any */
+ union acpi_generic_state *scope_info; /* Stack of nested scopes */
+ union acpi_parse_object *prev_op; /* Last op that was processed */
+ union acpi_parse_object *next_op; /* next op to be processed */
+ struct acpi_thread_state *thread;
+ acpi_parse_downwards descending_callback;
+ acpi_parse_upwards ascending_callback;
+};
+
+/* Info used by acpi_ps_init_objects */
+
+struct acpi_init_walk_info {
+ u16 method_count;
+ u16 device_count;
+ u16 op_region_count;
+ u16 field_count;
+ u16 buffer_count;
+ u16 package_count;
+ u16 op_region_init;
+ u16 field_init;
+ u16 buffer_init;
+ u16 package_init;
+ u16 object_count;
+ acpi_owner_id owner_id;
+ u32 table_index;
+};
+
+struct acpi_get_devices_info {
+ acpi_walk_callback user_function;
+ void *context;
+ const char *hid;
+};
+
+union acpi_aml_operands {
+ union acpi_operand_object *operands[7];
+
+ struct {
+ struct acpi_object_integer *type;
+ struct acpi_object_integer *code;
+ struct acpi_object_integer *argument;
+
+ } fatal;
+
+ struct {
+ union acpi_operand_object *source;
+ struct acpi_object_integer *index;
+ union acpi_operand_object *target;
+
+ } index;
+
+ struct {
+ union acpi_operand_object *source;
+ struct acpi_object_integer *index;
+ struct acpi_object_integer *length;
+ union acpi_operand_object *target;
+
+ } mid;
+};
+
+/*
+ * Structure used to pass object evaluation parameters.
+ * Purpose is to reduce CPU stack use.
+ */
+struct acpi_evaluate_info {
+ struct acpi_namespace_node *prefix_node;
+ char *pathname;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object **parameters;
+ struct acpi_namespace_node *resolved_node;
+ union acpi_operand_object *return_object;
+ u8 param_count;
+ u8 pass_number;
+ u8 return_object_type;
+ u8 flags;
+};
+
+/* Values for Flags above */
+
+#define ACPI_IGNORE_RETURN_VALUE 1
+
+/* Info used by acpi_ns_initialize_devices */
+
+struct acpi_device_walk_info {
+ u16 device_count;
+ u16 num_STA;
+ u16 num_INI;
+ struct acpi_table_desc *table_desc;
+ struct acpi_evaluate_info *evaluate_info;
+};
+
+/* TBD: [Restructure] Merge with struct above */
+
+struct acpi_walk_info {
+ u32 debug_level;
+ u32 count;
+ acpi_owner_id owner_id;
+ u8 display_type;
+};
+
+/* Display Types */
+
+#define ACPI_DISPLAY_SUMMARY (u8) 0
+#define ACPI_DISPLAY_OBJECTS (u8) 1
+#define ACPI_DISPLAY_MASK (u8) 1
+
+#define ACPI_DISPLAY_SHORT (u8) 2
+
+#endif
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
new file mode 100644
index 000000000000..7ce6e33c7f78
--- /dev/null
+++ b/drivers/acpi/acpica/actables.h
@@ -0,0 +1,117 @@
+/******************************************************************************
+ *
+ * Name: actables.h - ACPI table management
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __ACTABLES_H__
+#define __ACTABLES_H__
+
+acpi_status acpi_allocate_root_table(u32 initial_table_count);
+
+/*
+ * tbfadt - FADT parse/convert/validate
+ */
+void acpi_tb_parse_fadt(u32 table_index, u8 flags);
+
+void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length);
+
+/*
+ * tbfind - find ACPI table
+ */
+acpi_status
+acpi_tb_find_table(char *signature,
+ char *oem_id, char *oem_table_id, u32 *table_index);
+
+/*
+ * tbinstal - Table removal and deletion
+ */
+acpi_status acpi_tb_resize_root_table_list(void);
+
+acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc);
+
+acpi_status
+acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index);
+
+acpi_status
+acpi_tb_store_table(acpi_physical_address address,
+ struct acpi_table_header *table,
+ u32 length, u8 flags, u32 *table_index);
+
+void acpi_tb_delete_table(struct acpi_table_desc *table_desc);
+
+void acpi_tb_terminate(void);
+
+void acpi_tb_delete_namespace_by_owner(u32 table_index);
+
+acpi_status acpi_tb_allocate_owner_id(u32 table_index);
+
+acpi_status acpi_tb_release_owner_id(u32 table_index);
+
+acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id);
+
+u8 acpi_tb_is_table_loaded(u32 table_index);
+
+void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded);
+
+/*
+ * tbutils - table manager utilities
+ */
+acpi_status acpi_tb_initialize_facs(void);
+
+u8 acpi_tb_tables_loaded(void);
+
+void
+acpi_tb_print_table_header(acpi_physical_address address,
+ struct acpi_table_header *header);
+
+u8 acpi_tb_checksum(u8 *buffer, u32 length);
+
+acpi_status
+acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length);
+
+void
+acpi_tb_install_table(acpi_physical_address address,
+ u8 flags, char *signature, u32 table_index);
+
+acpi_status
+acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags);
+
+#endif /* __ACTABLES_H__ */
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
new file mode 100644
index 000000000000..80d8813484fe
--- /dev/null
+++ b/drivers/acpi/acpica/acutils.h
@@ -0,0 +1,549 @@
+/******************************************************************************
+ *
+ * Name: acutils.h -- prototypes for the common (subsystem-wide) procedures
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 _ACUTILS_H
+#define _ACUTILS_H
+
+extern const u8 acpi_gbl_resource_aml_sizes[];
+
+/* Strings used by the disassembler and debugger resource dump routines */
+
+#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
+
+extern const char *acpi_gbl_bm_decode[];
+extern const char *acpi_gbl_config_decode[];
+extern const char *acpi_gbl_consume_decode[];
+extern const char *acpi_gbl_dec_decode[];
+extern const char *acpi_gbl_he_decode[];
+extern const char *acpi_gbl_io_decode[];
+extern const char *acpi_gbl_ll_decode[];
+extern const char *acpi_gbl_max_decode[];
+extern const char *acpi_gbl_mem_decode[];
+extern const char *acpi_gbl_min_decode[];
+extern const char *acpi_gbl_mtp_decode[];
+extern const char *acpi_gbl_rng_decode[];
+extern const char *acpi_gbl_rw_decode[];
+extern const char *acpi_gbl_shr_decode[];
+extern const char *acpi_gbl_siz_decode[];
+extern const char *acpi_gbl_trs_decode[];
+extern const char *acpi_gbl_ttp_decode[];
+extern const char *acpi_gbl_typ_decode[];
+#endif
+
+/* Types for Resource descriptor entries */
+
+#define ACPI_INVALID_RESOURCE 0
+#define ACPI_FIXED_LENGTH 1
+#define ACPI_VARIABLE_LENGTH 2
+#define ACPI_SMALL_VARIABLE_LENGTH 3
+
+typedef
+acpi_status(*acpi_walk_aml_callback) (u8 * aml,
+ u32 length,
+ u32 offset,
+ u8 resource_index, void **context);
+
+typedef
+acpi_status(*acpi_pkg_callback) (u8 object_type,
+ union acpi_operand_object * source_object,
+ union acpi_generic_state * state,
+ void *context);
+
+struct acpi_pkg_info {
+ u8 *free_space;
+ acpi_size length;
+ u32 object_space;
+ u32 num_packages;
+};
+
+#define REF_INCREMENT (u16) 0
+#define REF_DECREMENT (u16) 1
+#define REF_FORCE_DELETE (u16) 2
+
+/* acpi_ut_dump_buffer */
+
+#define DB_BYTE_DISPLAY 1
+#define DB_WORD_DISPLAY 2
+#define DB_DWORD_DISPLAY 4
+#define DB_QWORD_DISPLAY 8
+
+/*
+ * utglobal - Global data structures and procedures
+ */
+acpi_status acpi_ut_init_globals(void);
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+
+char *acpi_ut_get_mutex_name(u32 mutex_id);
+
+const char *acpi_ut_get_notify_name(u32 notify_value);
+
+#endif
+
+char *acpi_ut_get_type_name(acpi_object_type type);
+
+char *acpi_ut_get_node_name(void *object);
+
+char *acpi_ut_get_descriptor_name(void *object);
+
+const char *acpi_ut_get_reference_name(union acpi_operand_object *object);
+
+char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc);
+
+char *acpi_ut_get_region_name(u8 space_id);
+
+char *acpi_ut_get_event_name(u32 event_id);
+
+char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position);
+
+u8 acpi_ut_valid_object_type(acpi_object_type type);
+
+/*
+ * utinit - miscellaneous initialization and shutdown
+ */
+acpi_status acpi_ut_hardware_initialize(void);
+
+void acpi_ut_subsystem_shutdown(void);
+
+/*
+ * utclib - Local implementations of C library functions
+ */
+#ifndef ACPI_USE_SYSTEM_CLIBRARY
+
+acpi_size acpi_ut_strlen(const char *string);
+
+char *acpi_ut_strcpy(char *dst_string, const char *src_string);
+
+char *acpi_ut_strncpy(char *dst_string,
+ const char *src_string, acpi_size count);
+
+int acpi_ut_memcmp(const char *buffer1, const char *buffer2, acpi_size count);
+
+int acpi_ut_strncmp(const char *string1, const char *string2, acpi_size count);
+
+int acpi_ut_strcmp(const char *string1, const char *string2);
+
+char *acpi_ut_strcat(char *dst_string, const char *src_string);
+
+char *acpi_ut_strncat(char *dst_string,
+ const char *src_string, acpi_size count);
+
+u32 acpi_ut_strtoul(const char *string, char **terminator, u32 base);
+
+char *acpi_ut_strstr(char *string1, char *string2);
+
+void *acpi_ut_memcpy(void *dest, const void *src, acpi_size count);
+
+void *acpi_ut_memset(void *dest, u8 value, acpi_size count);
+
+int acpi_ut_to_upper(int c);
+
+int acpi_ut_to_lower(int c);
+
+extern const u8 _acpi_ctype[];
+
+#define _ACPI_XA 0x00 /* extra alphabetic - not supported */
+#define _ACPI_XS 0x40 /* extra space */
+#define _ACPI_BB 0x00 /* BEL, BS, etc. - not supported */
+#define _ACPI_CN 0x20 /* CR, FF, HT, NL, VT */
+#define _ACPI_DI 0x04 /* '0'-'9' */
+#define _ACPI_LO 0x02 /* 'a'-'z' */
+#define _ACPI_PU 0x10 /* punctuation */
+#define _ACPI_SP 0x08 /* space */
+#define _ACPI_UP 0x01 /* 'A'-'Z' */
+#define _ACPI_XD 0x80 /* '0'-'9', 'A'-'F', 'a'-'f' */
+
+#define ACPI_IS_DIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_DI))
+#define ACPI_IS_SPACE(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_SP))
+#define ACPI_IS_XDIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_XD))
+#define ACPI_IS_UPPER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_UP))
+#define ACPI_IS_LOWER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO))
+#define ACPI_IS_PRINT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_SP | _ACPI_PU))
+#define ACPI_IS_ALPHA(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP))
+
+#endif /* ACPI_USE_SYSTEM_CLIBRARY */
+
+/*
+ * utcopy - Object construction and conversion interfaces
+ */
+acpi_status
+acpi_ut_build_simple_object(union acpi_operand_object *obj,
+ union acpi_object *user_obj,
+ u8 * data_space, u32 * buffer_space_used);
+
+acpi_status
+acpi_ut_build_package_object(union acpi_operand_object *obj,
+ u8 * buffer, u32 * space_used);
+
+acpi_status
+acpi_ut_copy_iobject_to_eobject(union acpi_operand_object *obj,
+ struct acpi_buffer *ret_buffer);
+
+acpi_status
+acpi_ut_copy_eobject_to_iobject(union acpi_object *obj,
+ union acpi_operand_object **internal_obj);
+
+acpi_status
+acpi_ut_copy_isimple_to_isimple(union acpi_operand_object *source_obj,
+ union acpi_operand_object *dest_obj);
+
+acpi_status
+acpi_ut_copy_iobject_to_iobject(union acpi_operand_object *source_desc,
+ union acpi_operand_object **dest_desc,
+ struct acpi_walk_state *walk_state);
+
+/*
+ * utcreate - Object creation
+ */
+acpi_status
+acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action);
+
+/*
+ * utdebug - Debug interfaces
+ */
+void acpi_ut_init_stack_ptr_trace(void);
+
+void acpi_ut_track_stack_ptr(void);
+
+void
+acpi_ut_trace(u32 line_number,
+ const char *function_name,
+ const char *module_name, u32 component_id);
+
+void
+acpi_ut_trace_ptr(u32 line_number,
+ const char *function_name,
+ const char *module_name, u32 component_id, void *pointer);
+
+void
+acpi_ut_trace_u32(u32 line_number,
+ const char *function_name,
+ const char *module_name, u32 component_id, u32 integer);
+
+void
+acpi_ut_trace_str(u32 line_number,
+ const char *function_name,
+ const char *module_name, u32 component_id, char *string);
+
+void
+acpi_ut_exit(u32 line_number,
+ const char *function_name,
+ const char *module_name, u32 component_id);
+
+void
+acpi_ut_status_exit(u32 line_number,
+ const char *function_name,
+ const char *module_name,
+ u32 component_id, acpi_status status);
+
+void
+acpi_ut_value_exit(u32 line_number,
+ const char *function_name,
+ const char *module_name,
+ u32 component_id, acpi_integer value);
+
+void
+acpi_ut_ptr_exit(u32 line_number,
+ const char *function_name,
+ const char *module_name, u32 component_id, u8 *ptr);
+
+void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id);
+
+void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display);
+
+void acpi_ut_report_error(char *module_name, u32 line_number);
+
+void acpi_ut_report_info(char *module_name, u32 line_number);
+
+void acpi_ut_report_warning(char *module_name, u32 line_number);
+
+/*
+ * utdelete - Object deletion and reference counts
+ */
+void acpi_ut_add_reference(union acpi_operand_object *object);
+
+void acpi_ut_remove_reference(union acpi_operand_object *object);
+
+void acpi_ut_delete_internal_package_object(union acpi_operand_object *object);
+
+void acpi_ut_delete_internal_simple_object(union acpi_operand_object *object);
+
+void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list);
+
+/*
+ * uteval - object evaluation
+ */
+acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
+ char *path,
+ u32 expected_return_btypes,
+ union acpi_operand_object **return_desc);
+
+acpi_status
+acpi_ut_evaluate_numeric_object(char *object_name,
+ struct acpi_namespace_node *device_node,
+ acpi_integer * address);
+
+acpi_status
+acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
+ struct acpica_device_id *hid);
+
+acpi_status
+acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
+ struct acpi_compatible_id_list **return_cid_list);
+
+acpi_status
+acpi_ut_execute_STA(struct acpi_namespace_node *device_node,
+ u32 * status_flags);
+
+acpi_status
+acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
+ struct acpica_device_id *uid);
+
+acpi_status
+acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest);
+
+/*
+ * utobject - internal object create/delete/cache routines
+ */
+union acpi_operand_object *acpi_ut_create_internal_object_dbg(const char
+ *module_name,
+ u32 line_number,
+ u32 component_id,
+ acpi_object_type
+ type);
+
+void *acpi_ut_allocate_object_desc_dbg(const char *module_name,
+ u32 line_number, u32 component_id);
+
+#define acpi_ut_create_internal_object(t) acpi_ut_create_internal_object_dbg (_acpi_module_name,__LINE__,_COMPONENT,t)
+#define acpi_ut_allocate_object_desc() acpi_ut_allocate_object_desc_dbg (_acpi_module_name,__LINE__,_COMPONENT)
+
+void acpi_ut_delete_object_desc(union acpi_operand_object *object);
+
+u8 acpi_ut_valid_internal_object(void *object);
+
+union acpi_operand_object *acpi_ut_create_package_object(u32 count);
+
+union acpi_operand_object *acpi_ut_create_buffer_object(acpi_size buffer_size);
+
+union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size);
+
+acpi_status
+acpi_ut_get_object_size(union acpi_operand_object *obj, acpi_size * obj_length);
+
+/*
+ * utstate - Generic state creation/cache routines
+ */
+void
+acpi_ut_push_generic_state(union acpi_generic_state **list_head,
+ union acpi_generic_state *state);
+
+union acpi_generic_state *acpi_ut_pop_generic_state(union acpi_generic_state
+ **list_head);
+
+union acpi_generic_state *acpi_ut_create_generic_state(void);
+
+struct acpi_thread_state *acpi_ut_create_thread_state(void);
+
+union acpi_generic_state *acpi_ut_create_update_state(union acpi_operand_object
+ *object, u16 action);
+
+union acpi_generic_state *acpi_ut_create_pkg_state(void *internal_object,
+ void *external_object,
+ u16 index);
+
+acpi_status
+acpi_ut_create_update_state_and_push(union acpi_operand_object *object,
+ u16 action,
+ union acpi_generic_state **state_list);
+
+#ifdef ACPI_FUTURE_USAGE
+acpi_status
+acpi_ut_create_pkg_state_and_push(void *internal_object,
+ void *external_object,
+ u16 index,
+ union acpi_generic_state **state_list);
+#endif /* ACPI_FUTURE_USAGE */
+
+union acpi_generic_state *acpi_ut_create_control_state(void);
+
+void acpi_ut_delete_generic_state(union acpi_generic_state *state);
+
+/*
+ * utmath
+ */
+acpi_status
+acpi_ut_divide(acpi_integer in_dividend,
+ acpi_integer in_divisor,
+ acpi_integer * out_quotient, acpi_integer * out_remainder);
+
+acpi_status
+acpi_ut_short_divide(acpi_integer in_dividend,
+ u32 divisor,
+ acpi_integer * out_quotient, u32 * out_remainder);
+
+/*
+ * utmisc
+ */
+const char *acpi_ut_validate_exception(acpi_status status);
+
+u8 acpi_ut_is_aml_table(struct acpi_table_header *table);
+
+acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id);
+
+void acpi_ut_release_owner_id(acpi_owner_id * owner_id);
+
+acpi_status
+acpi_ut_walk_package_tree(union acpi_operand_object *source_object,
+ void *target_object,
+ acpi_pkg_callback walk_callback, void *context);
+
+void acpi_ut_strupr(char *src_string);
+
+void acpi_ut_print_string(char *string, u8 max_length);
+
+u8 acpi_ut_valid_acpi_name(u32 name);
+
+acpi_name acpi_ut_repair_name(char *name);
+
+u8 acpi_ut_valid_acpi_char(char character, u32 position);
+
+acpi_status
+acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer);
+
+/* Values for Base above (16=Hex, 10=Decimal) */
+
+#define ACPI_ANY_BASE 0
+
+u32 acpi_ut_dword_byte_swap(u32 value);
+
+void acpi_ut_set_integer_width(u8 revision);
+
+#ifdef ACPI_DEBUG_OUTPUT
+void
+acpi_ut_display_init_pathname(u8 type,
+ struct acpi_namespace_node *obj_handle,
+ char *path);
+#endif
+
+/*
+ * utresrc
+ */
+acpi_status
+acpi_ut_walk_aml_resources(u8 * aml,
+ acpi_size aml_length,
+ acpi_walk_aml_callback user_function,
+ void **context);
+
+acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index);
+
+u32 acpi_ut_get_descriptor_length(void *aml);
+
+u16 acpi_ut_get_resource_length(void *aml);
+
+u8 acpi_ut_get_resource_header_length(void *aml);
+
+u8 acpi_ut_get_resource_type(void *aml);
+
+acpi_status
+acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc,
+ u8 ** end_tag);
+
+/*
+ * utmutex - mutex support
+ */
+acpi_status acpi_ut_mutex_initialize(void);
+
+void acpi_ut_mutex_terminate(void);
+
+acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id);
+
+acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id);
+
+/*
+ * utalloc - memory allocation and object caching
+ */
+acpi_status acpi_ut_create_caches(void);
+
+acpi_status acpi_ut_delete_caches(void);
+
+acpi_status acpi_ut_validate_buffer(struct acpi_buffer *buffer);
+
+acpi_status
+acpi_ut_initialize_buffer(struct acpi_buffer *buffer,
+ acpi_size required_length);
+
+void *acpi_ut_allocate(acpi_size size,
+ u32 component, const char *module, u32 line);
+
+void *acpi_ut_allocate_zeroed(acpi_size size,
+ u32 component, const char *module, u32 line);
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+void *acpi_ut_allocate_and_track(acpi_size size,
+ u32 component, const char *module, u32 line);
+
+void *acpi_ut_allocate_zeroed_and_track(acpi_size size,
+ u32 component,
+ const char *module, u32 line);
+
+void
+acpi_ut_free_and_track(void *address,
+ u32 component, const char *module, u32 line);
+
+#ifdef ACPI_FUTURE_USAGE
+void acpi_ut_dump_allocation_info(void);
+#endif /* ACPI_FUTURE_USAGE */
+
+void acpi_ut_dump_allocations(u32 component, const char *module);
+
+acpi_status
+acpi_ut_create_list(char *list_name,
+ u16 object_size, struct acpi_memory_list **return_cache);
+
+#endif
+
+#endif /* _ACUTILS_H */
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h
new file mode 100644
index 000000000000..ff851c5df698
--- /dev/null
+++ b/drivers/acpi/acpica/amlcode.h
@@ -0,0 +1,494 @@
+/******************************************************************************
+ *
+ * Name: amlcode.h - Definitions for AML, as included in "definition blocks"
+ * Declarations and definitions contained herein are derived
+ * directly from the ACPI specification.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 __AMLCODE_H__
+#define __AMLCODE_H__
+
+/* primary opcodes */
+
+#define AML_NULL_CHAR (u16) 0x00
+
+#define AML_ZERO_OP (u16) 0x00
+#define AML_ONE_OP (u16) 0x01
+#define AML_UNASSIGNED (u16) 0x02
+#define AML_ALIAS_OP (u16) 0x06
+#define AML_NAME_OP (u16) 0x08
+#define AML_BYTE_OP (u16) 0x0a
+#define AML_WORD_OP (u16) 0x0b
+#define AML_DWORD_OP (u16) 0x0c
+#define AML_STRING_OP (u16) 0x0d
+#define AML_QWORD_OP (u16) 0x0e /* ACPI 2.0 */
+#define AML_SCOPE_OP (u16) 0x10
+#define AML_BUFFER_OP (u16) 0x11
+#define AML_PACKAGE_OP (u16) 0x12
+#define AML_VAR_PACKAGE_OP (u16) 0x13 /* ACPI 2.0 */
+#define AML_METHOD_OP (u16) 0x14
+#define AML_DUAL_NAME_PREFIX (u16) 0x2e
+#define AML_MULTI_NAME_PREFIX_OP (u16) 0x2f
+#define AML_NAME_CHAR_SUBSEQ (u16) 0x30
+#define AML_NAME_CHAR_FIRST (u16) 0x41
+#define AML_EXTENDED_OP_PREFIX (u16) 0x5b
+#define AML_ROOT_PREFIX (u16) 0x5c
+#define AML_PARENT_PREFIX (u16) 0x5e
+#define AML_LOCAL_OP (u16) 0x60
+#define AML_LOCAL0 (u16) 0x60
+#define AML_LOCAL1 (u16) 0x61
+#define AML_LOCAL2 (u16) 0x62
+#define AML_LOCAL3 (u16) 0x63
+#define AML_LOCAL4 (u16) 0x64
+#define AML_LOCAL5 (u16) 0x65
+#define AML_LOCAL6 (u16) 0x66
+#define AML_LOCAL7 (u16) 0x67
+#define AML_ARG_OP (u16) 0x68
+#define AML_ARG0 (u16) 0x68
+#define AML_ARG1 (u16) 0x69
+#define AML_ARG2 (u16) 0x6a
+#define AML_ARG3 (u16) 0x6b
+#define AML_ARG4 (u16) 0x6c
+#define AML_ARG5 (u16) 0x6d
+#define AML_ARG6 (u16) 0x6e
+#define AML_STORE_OP (u16) 0x70
+#define AML_REF_OF_OP (u16) 0x71
+#define AML_ADD_OP (u16) 0x72
+#define AML_CONCAT_OP (u16) 0x73
+#define AML_SUBTRACT_OP (u16) 0x74
+#define AML_INCREMENT_OP (u16) 0x75
+#define AML_DECREMENT_OP (u16) 0x76
+#define AML_MULTIPLY_OP (u16) 0x77
+#define AML_DIVIDE_OP (u16) 0x78
+#define AML_SHIFT_LEFT_OP (u16) 0x79
+#define AML_SHIFT_RIGHT_OP (u16) 0x7a
+#define AML_BIT_AND_OP (u16) 0x7b
+#define AML_BIT_NAND_OP (u16) 0x7c
+#define AML_BIT_OR_OP (u16) 0x7d
+#define AML_BIT_NOR_OP (u16) 0x7e
+#define AML_BIT_XOR_OP (u16) 0x7f
+#define AML_BIT_NOT_OP (u16) 0x80
+#define AML_FIND_SET_LEFT_BIT_OP (u16) 0x81
+#define AML_FIND_SET_RIGHT_BIT_OP (u16) 0x82
+#define AML_DEREF_OF_OP (u16) 0x83
+#define AML_CONCAT_RES_OP (u16) 0x84 /* ACPI 2.0 */
+#define AML_MOD_OP (u16) 0x85 /* ACPI 2.0 */
+#define AML_NOTIFY_OP (u16) 0x86
+#define AML_SIZE_OF_OP (u16) 0x87
+#define AML_INDEX_OP (u16) 0x88
+#define AML_MATCH_OP (u16) 0x89
+#define AML_CREATE_DWORD_FIELD_OP (u16) 0x8a
+#define AML_CREATE_WORD_FIELD_OP (u16) 0x8b
+#define AML_CREATE_BYTE_FIELD_OP (u16) 0x8c
+#define AML_CREATE_BIT_FIELD_OP (u16) 0x8d
+#define AML_TYPE_OP (u16) 0x8e
+#define AML_CREATE_QWORD_FIELD_OP (u16) 0x8f /* ACPI 2.0 */
+#define AML_LAND_OP (u16) 0x90
+#define AML_LOR_OP (u16) 0x91
+#define AML_LNOT_OP (u16) 0x92
+#define AML_LEQUAL_OP (u16) 0x93
+#define AML_LGREATER_OP (u16) 0x94
+#define AML_LLESS_OP (u16) 0x95
+#define AML_TO_BUFFER_OP (u16) 0x96 /* ACPI 2.0 */
+#define AML_TO_DECSTRING_OP (u16) 0x97 /* ACPI 2.0 */
+#define AML_TO_HEXSTRING_OP (u16) 0x98 /* ACPI 2.0 */
+#define AML_TO_INTEGER_OP (u16) 0x99 /* ACPI 2.0 */
+#define AML_TO_STRING_OP (u16) 0x9c /* ACPI 2.0 */
+#define AML_COPY_OP (u16) 0x9d /* ACPI 2.0 */
+#define AML_MID_OP (u16) 0x9e /* ACPI 2.0 */
+#define AML_CONTINUE_OP (u16) 0x9f /* ACPI 2.0 */
+#define AML_IF_OP (u16) 0xa0
+#define AML_ELSE_OP (u16) 0xa1
+#define AML_WHILE_OP (u16) 0xa2
+#define AML_NOOP_OP (u16) 0xa3
+#define AML_RETURN_OP (u16) 0xa4
+#define AML_BREAK_OP (u16) 0xa5
+#define AML_BREAK_POINT_OP (u16) 0xcc
+#define AML_ONES_OP (u16) 0xff
+
+/* prefixed opcodes */
+
+#define AML_EXTENDED_OPCODE (u16) 0x5b00 /* prefix for 2-byte opcodes */
+
+#define AML_MUTEX_OP (u16) 0x5b01
+#define AML_EVENT_OP (u16) 0x5b02
+#define AML_SHIFT_RIGHT_BIT_OP (u16) 0x5b10
+#define AML_SHIFT_LEFT_BIT_OP (u16) 0x5b11
+#define AML_COND_REF_OF_OP (u16) 0x5b12
+#define AML_CREATE_FIELD_OP (u16) 0x5b13
+#define AML_LOAD_TABLE_OP (u16) 0x5b1f /* ACPI 2.0 */
+#define AML_LOAD_OP (u16) 0x5b20
+#define AML_STALL_OP (u16) 0x5b21
+#define AML_SLEEP_OP (u16) 0x5b22
+#define AML_ACQUIRE_OP (u16) 0x5b23
+#define AML_SIGNAL_OP (u16) 0x5b24
+#define AML_WAIT_OP (u16) 0x5b25
+#define AML_RESET_OP (u16) 0x5b26
+#define AML_RELEASE_OP (u16) 0x5b27
+#define AML_FROM_BCD_OP (u16) 0x5b28
+#define AML_TO_BCD_OP (u16) 0x5b29
+#define AML_UNLOAD_OP (u16) 0x5b2a
+#define AML_REVISION_OP (u16) 0x5b30
+#define AML_DEBUG_OP (u16) 0x5b31
+#define AML_FATAL_OP (u16) 0x5b32
+#define AML_TIMER_OP (u16) 0x5b33 /* ACPI 3.0 */
+#define AML_REGION_OP (u16) 0x5b80
+#define AML_FIELD_OP (u16) 0x5b81
+#define AML_DEVICE_OP (u16) 0x5b82
+#define AML_PROCESSOR_OP (u16) 0x5b83
+#define AML_POWER_RES_OP (u16) 0x5b84
+#define AML_THERMAL_ZONE_OP (u16) 0x5b85
+#define AML_INDEX_FIELD_OP (u16) 0x5b86
+#define AML_BANK_FIELD_OP (u16) 0x5b87
+#define AML_DATA_REGION_OP (u16) 0x5b88 /* ACPI 2.0 */
+
+/*
+ * Combination opcodes (actually two one-byte opcodes)
+ * Used by the disassembler and i_aSL compiler
+ */
+#define AML_LGREATEREQUAL_OP (u16) 0x9295
+#define AML_LLESSEQUAL_OP (u16) 0x9294
+#define AML_LNOTEQUAL_OP (u16) 0x9293
+
+/*
+ * Internal opcodes
+ * Use only "Unknown" AML opcodes, don't attempt to use
+ * any valid ACPI ASCII values (A-Z, 0-9, '-')
+ */
+#define AML_INT_NAMEPATH_OP (u16) 0x002d
+#define AML_INT_NAMEDFIELD_OP (u16) 0x0030
+#define AML_INT_RESERVEDFIELD_OP (u16) 0x0031
+#define AML_INT_ACCESSFIELD_OP (u16) 0x0032
+#define AML_INT_BYTELIST_OP (u16) 0x0033
+#define AML_INT_STATICSTRING_OP (u16) 0x0034
+#define AML_INT_METHODCALL_OP (u16) 0x0035
+#define AML_INT_RETURN_VALUE_OP (u16) 0x0036
+#define AML_INT_EVAL_SUBTREE_OP (u16) 0x0037
+
+#define ARG_NONE 0x0
+
+/*
+ * Argument types for the AML Parser
+ * Each field in the arg_types u32 is 5 bits, allowing for a maximum of 6 arguments.
+ * There can be up to 31 unique argument types
+ * Zero is reserved as end-of-list indicator
+ */
+#define ARGP_BYTEDATA 0x01
+#define ARGP_BYTELIST 0x02
+#define ARGP_CHARLIST 0x03
+#define ARGP_DATAOBJ 0x04
+#define ARGP_DATAOBJLIST 0x05
+#define ARGP_DWORDDATA 0x06
+#define ARGP_FIELDLIST 0x07
+#define ARGP_NAME 0x08
+#define ARGP_NAMESTRING 0x09
+#define ARGP_OBJLIST 0x0A
+#define ARGP_PKGLENGTH 0x0B
+#define ARGP_SUPERNAME 0x0C
+#define ARGP_TARGET 0x0D
+#define ARGP_TERMARG 0x0E
+#define ARGP_TERMLIST 0x0F
+#define ARGP_WORDDATA 0x10
+#define ARGP_QWORDDATA 0x11
+#define ARGP_SIMPLENAME 0x12
+
+/*
+ * Resolved argument types for the AML Interpreter
+ * Each field in the arg_types u32 is 5 bits, allowing for a maximum of 6 arguments.
+ * There can be up to 31 unique argument types (0 is end-of-arg-list indicator)
+ *
+ * Note1: These values are completely independent from the ACPI_TYPEs
+ * i.e., ARGI_INTEGER != ACPI_TYPE_INTEGER
+ *
+ * Note2: If and when 5 bits becomes insufficient, it would probably be best
+ * to convert to a 6-byte array of argument types, allowing 8 bits per argument.
+ */
+
+/* Single, simple types */
+
+#define ARGI_ANYTYPE 0x01 /* Don't care */
+#define ARGI_PACKAGE 0x02
+#define ARGI_EVENT 0x03
+#define ARGI_MUTEX 0x04
+#define ARGI_DDBHANDLE 0x05
+
+/* Interchangeable types (via implicit conversion) */
+
+#define ARGI_INTEGER 0x06
+#define ARGI_STRING 0x07
+#define ARGI_BUFFER 0x08
+#define ARGI_BUFFER_OR_STRING 0x09 /* Used by MID op only */
+#define ARGI_COMPUTEDATA 0x0A /* Buffer, String, or Integer */
+
+/* Reference objects */
+
+#define ARGI_INTEGER_REF 0x0B
+#define ARGI_OBJECT_REF 0x0C
+#define ARGI_DEVICE_REF 0x0D
+#define ARGI_REFERENCE 0x0E
+#define ARGI_TARGETREF 0x0F /* Target, subject to implicit conversion */
+#define ARGI_FIXED_TARGET 0x10 /* Target, no implicit conversion */
+#define ARGI_SIMPLE_TARGET 0x11 /* Name, Local, Arg -- no implicit conversion */
+
+/* Multiple/complex types */
+
+#define ARGI_DATAOBJECT 0x12 /* Buffer, String, package or reference to a Node - Used only by size_of operator */
+#define ARGI_COMPLEXOBJ 0x13 /* Buffer, String, or package (Used by INDEX op only) */
+#define ARGI_REF_OR_STRING 0x14 /* Reference or String (Used by DEREFOF op only) */
+#define ARGI_REGION_OR_BUFFER 0x15 /* Used by LOAD op only */
+#define ARGI_DATAREFOBJ 0x16
+
+/* Note: types above can expand to 0x1F maximum */
+
+#define ARGI_INVALID_OPCODE 0xFFFFFFFF
+
+/*
+ * hash offsets
+ */
+#define AML_EXTOP_HASH_OFFSET 22
+#define AML_LNOT_HASH_OFFSET 19
+
+/*
+ * opcode groups and types
+ */
+#define OPGRP_NAMED 0x01
+#define OPGRP_FIELD 0x02
+#define OPGRP_BYTELIST 0x04
+
+/*
+ * Opcode information
+ */
+
+/* Opcode flags */
+
+#define AML_LOGICAL 0x0001
+#define AML_LOGICAL_NUMERIC 0x0002
+#define AML_MATH 0x0004
+#define AML_CREATE 0x0008
+#define AML_FIELD 0x0010
+#define AML_DEFER 0x0020
+#define AML_NAMED 0x0040
+#define AML_NSNODE 0x0080
+#define AML_NSOPCODE 0x0100
+#define AML_NSOBJECT 0x0200
+#define AML_HAS_RETVAL 0x0400
+#define AML_HAS_TARGET 0x0800
+#define AML_HAS_ARGS 0x1000
+#define AML_CONSTANT 0x2000
+#define AML_NO_OPERAND_RESOLVE 0x4000
+
+/* Convenient flag groupings */
+
+#define AML_FLAGS_EXEC_0A_0T_1R AML_HAS_RETVAL
+#define AML_FLAGS_EXEC_1A_0T_0R AML_HAS_ARGS /* Monadic1 */
+#define AML_FLAGS_EXEC_1A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL /* Monadic2 */
+#define AML_FLAGS_EXEC_1A_1T_0R AML_HAS_ARGS | AML_HAS_TARGET
+#define AML_FLAGS_EXEC_1A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL /* monadic2_r */
+#define AML_FLAGS_EXEC_2A_0T_0R AML_HAS_ARGS /* Dyadic1 */
+#define AML_FLAGS_EXEC_2A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL /* Dyadic2 */
+#define AML_FLAGS_EXEC_2A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL /* dyadic2_r */
+#define AML_FLAGS_EXEC_2A_2T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL
+#define AML_FLAGS_EXEC_3A_0T_0R AML_HAS_ARGS
+#define AML_FLAGS_EXEC_3A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL
+#define AML_FLAGS_EXEC_6A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL
+
+/*
+ * The opcode Type is used in a dispatch table, do not change
+ * without updating the table.
+ */
+#define AML_TYPE_EXEC_0A_0T_1R 0x00
+#define AML_TYPE_EXEC_1A_0T_0R 0x01 /* Monadic1 */
+#define AML_TYPE_EXEC_1A_0T_1R 0x02 /* Monadic2 */
+#define AML_TYPE_EXEC_1A_1T_0R 0x03
+#define AML_TYPE_EXEC_1A_1T_1R 0x04 /* monadic2_r */
+#define AML_TYPE_EXEC_2A_0T_0R 0x05 /* Dyadic1 */
+#define AML_TYPE_EXEC_2A_0T_1R 0x06 /* Dyadic2 */
+#define AML_TYPE_EXEC_2A_1T_1R 0x07 /* dyadic2_r */
+#define AML_TYPE_EXEC_2A_2T_1R 0x08
+#define AML_TYPE_EXEC_3A_0T_0R 0x09
+#define AML_TYPE_EXEC_3A_1T_1R 0x0A
+#define AML_TYPE_EXEC_6A_0T_1R 0x0B
+/* End of types used in dispatch table */
+
+#define AML_TYPE_LITERAL 0x0B
+#define AML_TYPE_CONSTANT 0x0C
+#define AML_TYPE_METHOD_ARGUMENT 0x0D
+#define AML_TYPE_LOCAL_VARIABLE 0x0E
+#define AML_TYPE_DATA_TERM 0x0F
+
+/* Generic for an op that returns a value */
+
+#define AML_TYPE_METHOD_CALL 0x10
+
+/* Misc */
+
+#define AML_TYPE_CREATE_FIELD 0x11
+#define AML_TYPE_CREATE_OBJECT 0x12
+#define AML_TYPE_CONTROL 0x13
+#define AML_TYPE_NAMED_NO_OBJ 0x14
+#define AML_TYPE_NAMED_FIELD 0x15
+#define AML_TYPE_NAMED_SIMPLE 0x16
+#define AML_TYPE_NAMED_COMPLEX 0x17
+#define AML_TYPE_RETURN 0x18
+
+#define AML_TYPE_UNDEFINED 0x19
+#define AML_TYPE_BOGUS 0x1A
+
+/* AML Package Length encodings */
+
+#define ACPI_AML_PACKAGE_TYPE1 0x40
+#define ACPI_AML_PACKAGE_TYPE2 0x4000
+#define ACPI_AML_PACKAGE_TYPE3 0x400000
+#define ACPI_AML_PACKAGE_TYPE4 0x40000000
+
+/*
+ * Opcode classes
+ */
+#define AML_CLASS_EXECUTE 0x00
+#define AML_CLASS_CREATE 0x01
+#define AML_CLASS_ARGUMENT 0x02
+#define AML_CLASS_NAMED_OBJECT 0x03
+#define AML_CLASS_CONTROL 0x04
+#define AML_CLASS_ASCII 0x05
+#define AML_CLASS_PREFIX 0x06
+#define AML_CLASS_INTERNAL 0x07
+#define AML_CLASS_RETURN_VALUE 0x08
+#define AML_CLASS_METHOD_CALL 0x09
+#define AML_CLASS_UNKNOWN 0x0A
+
+/* Predefined Operation Region space_iDs */
+
+typedef enum {
+ REGION_MEMORY = 0,
+ REGION_IO,
+ REGION_PCI_CONFIG,
+ REGION_EC,
+ REGION_SMBUS,
+ REGION_CMOS,
+ REGION_PCI_BAR,
+ REGION_DATA_TABLE, /* Internal use only */
+ REGION_FIXED_HW = 0x7F
+} AML_REGION_TYPES;
+
+/* Comparison operation codes for match_op operator */
+
+typedef enum {
+ MATCH_MTR = 0,
+ MATCH_MEQ = 1,
+ MATCH_MLE = 2,
+ MATCH_MLT = 3,
+ MATCH_MGE = 4,
+ MATCH_MGT = 5
+} AML_MATCH_OPERATOR;
+
+#define MAX_MATCH_OPERATOR 5
+
+/*
+ * field_flags
+ *
+ * This byte is extracted from the AML and includes three separate
+ * pieces of information about the field:
+ * 1) The field access type
+ * 2) The field update rule
+ * 3) The lock rule for the field
+ *
+ * Bits 00 - 03 : access_type (any_acc, byte_acc, etc.)
+ * 04 : lock_rule (1 == Lock)
+ * 05 - 06 : update_rule
+ */
+#define AML_FIELD_ACCESS_TYPE_MASK 0x0F
+#define AML_FIELD_LOCK_RULE_MASK 0x10
+#define AML_FIELD_UPDATE_RULE_MASK 0x60
+
+/* 1) Field Access Types */
+
+typedef enum {
+ AML_FIELD_ACCESS_ANY = 0x00,
+ AML_FIELD_ACCESS_BYTE = 0x01,
+ AML_FIELD_ACCESS_WORD = 0x02,
+ AML_FIELD_ACCESS_DWORD = 0x03,
+ AML_FIELD_ACCESS_QWORD = 0x04, /* ACPI 2.0 */
+ AML_FIELD_ACCESS_BUFFER = 0x05 /* ACPI 2.0 */
+} AML_ACCESS_TYPE;
+
+/* 2) Field Lock Rules */
+
+typedef enum {
+ AML_FIELD_LOCK_NEVER = 0x00,
+ AML_FIELD_LOCK_ALWAYS = 0x10
+} AML_LOCK_RULE;
+
+/* 3) Field Update Rules */
+
+typedef enum {
+ AML_FIELD_UPDATE_PRESERVE = 0x00,
+ AML_FIELD_UPDATE_WRITE_AS_ONES = 0x20,
+ AML_FIELD_UPDATE_WRITE_AS_ZEROS = 0x40
+} AML_UPDATE_RULE;
+
+/*
+ * Field Access Attributes.
+ * This byte is extracted from the AML via the
+ * access_as keyword
+ */
+typedef enum {
+ AML_FIELD_ATTRIB_SMB_QUICK = 0x02,
+ AML_FIELD_ATTRIB_SMB_SEND_RCV = 0x04,
+ AML_FIELD_ATTRIB_SMB_BYTE = 0x06,
+ AML_FIELD_ATTRIB_SMB_WORD = 0x08,
+ AML_FIELD_ATTRIB_SMB_BLOCK = 0x0A,
+ AML_FIELD_ATTRIB_SMB_WORD_CALL = 0x0C,
+ AML_FIELD_ATTRIB_SMB_BLOCK_CALL = 0x0D
+} AML_ACCESS_ATTRIBUTE;
+
+/* Bit fields in method_flags byte */
+
+#define AML_METHOD_ARG_COUNT 0x07
+#define AML_METHOD_SERIALIZED 0x08
+#define AML_METHOD_SYNCH_LEVEL 0xF0
+
+/* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */
+
+#define AML_METHOD_INTERNAL_ONLY 0x01
+#define AML_METHOD_RESERVED1 0x02
+#define AML_METHOD_RESERVED2 0x04
+
+#endif /* __AMLCODE_H__ */
diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h
new file mode 100644
index 000000000000..7b070e42b7c5
--- /dev/null
+++ b/drivers/acpi/acpica/amlresrc.h
@@ -0,0 +1,311 @@
+
+/******************************************************************************
+ *
+ * Module Name: amlresrc.h - AML resource descriptors
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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.
+ */
+
+/* acpisrc:struct_defs -- for acpisrc conversion */
+
+#ifndef __AMLRESRC_H
+#define __AMLRESRC_H
+
+/*
+ * Resource descriptor tags, as defined in the ACPI specification.
+ * Used to symbolically reference fields within a descriptor.
+ */
+#define ACPI_RESTAG_ADDRESS "_ADR"
+#define ACPI_RESTAG_ALIGNMENT "_ALN"
+#define ACPI_RESTAG_ADDRESSSPACE "_ASI"
+#define ACPI_RESTAG_ACCESSSIZE "_ASZ"
+#define ACPI_RESTAG_TYPESPECIFICATTRIBUTES "_ATT"
+#define ACPI_RESTAG_BASEADDRESS "_BAS"
+#define ACPI_RESTAG_BUSMASTER "_BM_" /* Master(1), Slave(0) */
+#define ACPI_RESTAG_DECODE "_DEC"
+#define ACPI_RESTAG_DMA "_DMA"
+#define ACPI_RESTAG_DMATYPE "_TYP" /* Compatible(0), A(1), B(2), F(3) */
+#define ACPI_RESTAG_GRANULARITY "_GRA"
+#define ACPI_RESTAG_INTERRUPT "_INT"
+#define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* active_lo(1), active_hi(0) */
+#define ACPI_RESTAG_INTERRUPTSHARE "_SHR" /* Shareable(1), no_share(0) */
+#define ACPI_RESTAG_INTERRUPTTYPE "_HE_" /* Edge(1), Level(0) */
+#define ACPI_RESTAG_LENGTH "_LEN"
+#define ACPI_RESTAG_MEMATTRIBUTES "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */
+#define ACPI_RESTAG_MEMTYPE "_MEM" /* non_cache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */
+#define ACPI_RESTAG_MAXADDR "_MAX"
+#define ACPI_RESTAG_MINADDR "_MIN"
+#define ACPI_RESTAG_MAXTYPE "_MAF"
+#define ACPI_RESTAG_MINTYPE "_MIF"
+#define ACPI_RESTAG_REGISTERBITOFFSET "_RBO"
+#define ACPI_RESTAG_REGISTERBITWIDTH "_RBW"
+#define ACPI_RESTAG_RANGETYPE "_RNG"
+#define ACPI_RESTAG_READWRITETYPE "_RW_" /* read_only(0), Writeable (1) */
+#define ACPI_RESTAG_TRANSLATION "_TRA"
+#define ACPI_RESTAG_TRANSTYPE "_TRS" /* Sparse(1), Dense(0) */
+#define ACPI_RESTAG_TYPE "_TTP" /* Translation(1), Static (0) */
+#define ACPI_RESTAG_XFERTYPE "_SIZ" /* 8(0), 8_and16(1), 16(2) */
+
+/* Default sizes for "small" resource descriptors */
+
+#define ASL_RDESC_IRQ_SIZE 0x02
+#define ASL_RDESC_DMA_SIZE 0x02
+#define ASL_RDESC_ST_DEPEND_SIZE 0x00
+#define ASL_RDESC_END_DEPEND_SIZE 0x00
+#define ASL_RDESC_IO_SIZE 0x07
+#define ASL_RDESC_FIXED_IO_SIZE 0x03
+#define ASL_RDESC_END_TAG_SIZE 0x01
+
+struct asl_resource_node {
+ u32 buffer_length;
+ void *buffer;
+ struct asl_resource_node *next;
+};
+
+/* Macros used to generate AML resource length fields */
+
+#define ACPI_AML_SIZE_LARGE(r) (sizeof (r) - sizeof (struct aml_resource_large_header))
+#define ACPI_AML_SIZE_SMALL(r) (sizeof (r) - sizeof (struct aml_resource_small_header))
+
+/*
+ * Resource descriptors defined in the ACPI specification.
+ *
+ * Packing/alignment must be BYTE because these descriptors
+ * are used to overlay the raw AML byte stream.
+ */
+#pragma pack(1)
+
+/*
+ * SMALL descriptors
+ */
+#define AML_RESOURCE_SMALL_HEADER_COMMON \
+ u8 descriptor_type;
+
+struct aml_resource_small_header {
+AML_RESOURCE_SMALL_HEADER_COMMON};
+
+struct aml_resource_irq {
+ AML_RESOURCE_SMALL_HEADER_COMMON u16 irq_mask;
+ u8 flags;
+};
+
+struct aml_resource_irq_noflags {
+ AML_RESOURCE_SMALL_HEADER_COMMON u16 irq_mask;
+};
+
+struct aml_resource_dma {
+ AML_RESOURCE_SMALL_HEADER_COMMON u8 dma_channel_mask;
+ u8 flags;
+};
+
+struct aml_resource_start_dependent {
+ AML_RESOURCE_SMALL_HEADER_COMMON u8 flags;
+};
+
+struct aml_resource_start_dependent_noprio {
+AML_RESOURCE_SMALL_HEADER_COMMON};
+
+struct aml_resource_end_dependent {
+AML_RESOURCE_SMALL_HEADER_COMMON};
+
+struct aml_resource_io {
+ AML_RESOURCE_SMALL_HEADER_COMMON u8 flags;
+ u16 minimum;
+ u16 maximum;
+ u8 alignment;
+ u8 address_length;
+};
+
+struct aml_resource_fixed_io {
+ AML_RESOURCE_SMALL_HEADER_COMMON u16 address;
+ u8 address_length;
+};
+
+struct aml_resource_vendor_small {
+AML_RESOURCE_SMALL_HEADER_COMMON};
+
+struct aml_resource_end_tag {
+ AML_RESOURCE_SMALL_HEADER_COMMON u8 checksum;
+};
+
+/*
+ * LARGE descriptors
+ */
+#define AML_RESOURCE_LARGE_HEADER_COMMON \
+ u8 descriptor_type;\
+ u16 resource_length;
+
+struct aml_resource_large_header {
+AML_RESOURCE_LARGE_HEADER_COMMON};
+
+struct aml_resource_memory24 {
+ AML_RESOURCE_LARGE_HEADER_COMMON u8 flags;
+ u16 minimum;
+ u16 maximum;
+ u16 alignment;
+ u16 address_length;
+};
+
+struct aml_resource_vendor_large {
+AML_RESOURCE_LARGE_HEADER_COMMON};
+
+struct aml_resource_memory32 {
+ AML_RESOURCE_LARGE_HEADER_COMMON u8 flags;
+ u32 minimum;
+ u32 maximum;
+ u32 alignment;
+ u32 address_length;
+};
+
+struct aml_resource_fixed_memory32 {
+ AML_RESOURCE_LARGE_HEADER_COMMON u8 flags;
+ u32 address;
+ u32 address_length;
+};
+
+#define AML_RESOURCE_ADDRESS_COMMON \
+ u8 resource_type; \
+ u8 flags; \
+ u8 specific_flags;
+
+struct aml_resource_address {
+AML_RESOURCE_LARGE_HEADER_COMMON AML_RESOURCE_ADDRESS_COMMON};
+
+struct aml_resource_extended_address64 {
+ AML_RESOURCE_LARGE_HEADER_COMMON
+ AML_RESOURCE_ADDRESS_COMMON u8 revision_iD;
+ u8 reserved;
+ u64 granularity;
+ u64 minimum;
+ u64 maximum;
+ u64 translation_offset;
+ u64 address_length;
+ u64 type_specific;
+};
+
+#define AML_RESOURCE_EXTENDED_ADDRESS_REVISION 1 /* ACPI 3.0 */
+
+struct aml_resource_address64 {
+ AML_RESOURCE_LARGE_HEADER_COMMON
+ AML_RESOURCE_ADDRESS_COMMON u64 granularity;
+ u64 minimum;
+ u64 maximum;
+ u64 translation_offset;
+ u64 address_length;
+};
+
+struct aml_resource_address32 {
+ AML_RESOURCE_LARGE_HEADER_COMMON
+ AML_RESOURCE_ADDRESS_COMMON u32 granularity;
+ u32 minimum;
+ u32 maximum;
+ u32 translation_offset;
+ u32 address_length;
+};
+
+struct aml_resource_address16 {
+ AML_RESOURCE_LARGE_HEADER_COMMON
+ AML_RESOURCE_ADDRESS_COMMON u16 granularity;
+ u16 minimum;
+ u16 maximum;
+ u16 translation_offset;
+ u16 address_length;
+};
+
+struct aml_resource_extended_irq {
+ AML_RESOURCE_LARGE_HEADER_COMMON u8 flags;
+ u8 interrupt_count;
+ u32 interrupts[1];
+ /* res_source_index, res_source optional fields follow */
+};
+
+struct aml_resource_generic_register {
+ AML_RESOURCE_LARGE_HEADER_COMMON u8 address_space_id;
+ u8 bit_width;
+ u8 bit_offset;
+ u8 access_size; /* ACPI 3.0, was previously Reserved */
+ u64 address;
+};
+
+/* restore default alignment */
+
+#pragma pack()
+
+/* Union of all resource descriptors, so we can allocate the worst case */
+
+union aml_resource {
+ /* Descriptor headers */
+
+ u8 descriptor_type;
+ struct aml_resource_small_header small_header;
+ struct aml_resource_large_header large_header;
+
+ /* Small resource descriptors */
+
+ struct aml_resource_irq irq;
+ struct aml_resource_dma dma;
+ struct aml_resource_start_dependent start_dpf;
+ struct aml_resource_end_dependent end_dpf;
+ struct aml_resource_io io;
+ struct aml_resource_fixed_io fixed_io;
+ struct aml_resource_vendor_small vendor_small;
+ struct aml_resource_end_tag end_tag;
+
+ /* Large resource descriptors */
+
+ struct aml_resource_memory24 memory24;
+ struct aml_resource_generic_register generic_reg;
+ struct aml_resource_vendor_large vendor_large;
+ struct aml_resource_memory32 memory32;
+ struct aml_resource_fixed_memory32 fixed_memory32;
+ struct aml_resource_address16 address16;
+ struct aml_resource_address32 address32;
+ struct aml_resource_address64 address64;
+ struct aml_resource_extended_address64 ext_address64;
+ struct aml_resource_extended_irq extended_irq;
+
+ /* Utility overlays */
+
+ struct aml_resource_address address;
+ u32 dword_item;
+ u16 word_item;
+ u8 byte_item;
+};
+
+#endif
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/acpica/dsfield.c
index f988a5e7d2b4..53e27bc5a734 100644
--- a/drivers/acpi/dispatcher/dsfield.c
+++ b/drivers/acpi/acpica/dsfield.c
@@ -42,11 +42,12 @@
*/
#include <acpi/acpi.h>
-#include <acpi/amlcode.h>
-#include <acpi/acdispat.h>
-#include <acpi/acinterp.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acparser.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#include "acparser.h"
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsfield")
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/acpica/dsinit.c
index 949f7c75029e..eb144b13d8fa 100644
--- a/drivers/acpi/dispatcher/dsinit.c
+++ b/drivers/acpi/acpica/dsinit.c
@@ -42,9 +42,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acdispat.h>
-#include <acpi/acnamesp.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "acdispat.h"
+#include "acnamesp.h"
+#include "actables.h"
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsinit")
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index 279a5a60a0dd..14b8b8ed8023 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -42,11 +42,14 @@
*/
#include <acpi/acpi.h>
-#include <acpi/amlcode.h>
-#include <acpi/acdispat.h>
-#include <acpi/acinterp.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#ifdef ACPI_DISASSEMBLER
#include <acpi/acdisasm.h>
+#endif
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsmethod")
@@ -412,6 +415,9 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
status = obj_desc->method.implementation(next_walk_state);
+ if (status == AE_OK) {
+ status = AE_CTRL_TERMINATE;
+ }
}
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c
index d03f81bd1bcb..da0f5468184c 100644
--- a/drivers/acpi/dispatcher/dsmthdat.c
+++ b/drivers/acpi/acpica/dsmthdat.c
@@ -42,9 +42,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acdispat.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acdispat.h"
+#include "acnamesp.h"
+#include "acinterp.h"
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsmthdat")
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/acpica/dsobject.c
index 4f08e599d07e..15c628e6aa00 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/acpica/dsobject.c
@@ -42,11 +42,12 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/amlcode.h>
-#include <acpi/acdispat.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acnamesp.h"
+#include "acinterp.h"
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsobject")
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index 69fae5905bb8..0c3b4dd60e8a 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -43,13 +43,14 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/amlcode.h>
-#include <acpi/acdispat.h>
-#include <acpi/acinterp.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acevents.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#include "acevents.h"
+#include "actables.h"
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsopcode")
@@ -1140,10 +1141,29 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
op->common.aml_opcode, walk_state));
switch (op->common.aml_opcode) {
- case AML_IF_OP:
case AML_WHILE_OP:
/*
+ * If this is an additional iteration of a while loop, continue.
+ * There is no need to allocate a new control state.
+ */
+ if (walk_state->control_state) {
+ if (walk_state->control_state->control.aml_predicate_start
+ == (walk_state->parser_state.aml - 1)) {
+
+ /* Reset the state to start-of-loop */
+
+ walk_state->control_state->common.state =
+ ACPI_CONTROL_CONDITIONAL_EXECUTING;
+ break;
+ }
+ }
+
+ /*lint -fallthrough */
+
+ case AML_IF_OP:
+
+ /*
* IF/WHILE: Create a new control state to manage these
* constructs. We need to manage these as a stack, in order
* to handle nesting.
@@ -1243,13 +1263,36 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));
- if (walk_state->control_state->common.value) {
+ control_state = walk_state->control_state;
+ if (control_state->common.value) {
- /* Predicate was true, go back and evaluate it again! */
+ /* Predicate was true, the body of the loop was just executed */
+ /*
+ * This loop counter mechanism allows the interpreter to escape
+ * possibly infinite loops. This can occur in poorly written AML
+ * when the hardware does not respond within a while loop and the
+ * loop does not implement a timeout.
+ */
+ control_state->control.loop_count++;
+ if (control_state->control.loop_count >
+ ACPI_MAX_LOOP_ITERATIONS) {
+ status = AE_AML_INFINITE_LOOP;
+ break;
+ }
+
+ /*
+ * Go back and evaluate the predicate and maybe execute the loop
+ * another time
+ */
status = AE_CTRL_PENDING;
+ walk_state->aml_last_while =
+ control_state->control.aml_predicate_start;
+ break;
}
+ /* Predicate was false, terminate this while loop */
+
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"[WHILE_OP] termination! Op=%p\n", op));
@@ -1257,9 +1300,6 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
control_state =
acpi_ut_pop_generic_state(&walk_state->control_state);
-
- walk_state->aml_last_while =
- control_state->control.aml_predicate_start;
acpi_ut_delete_generic_state(control_state);
break;
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/acpica/dsutils.c
index b398982f0d8b..dabc23a46176 100644
--- a/drivers/acpi/dispatcher/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -42,12 +42,13 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/amlcode.h>
-#include <acpi/acdispat.h>
-#include <acpi/acinterp.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acdebug.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#include "acdebug.h"
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsutils")
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/acpica/dswexec.c
index 396fe12078cd..350e6656bc89 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -43,12 +43,13 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/amlcode.h>
-#include <acpi/acdispat.h>
-#include <acpi/acinterp.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acdebug.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#include "acdebug.h"
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dswexec")
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/acpica/dswload.c
index dff7a3e445a8..3023ceaa8d54 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/acpica/dswload.c
@@ -42,12 +42,13 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/amlcode.h>
-#include <acpi/acdispat.h>
-#include <acpi/acinterp.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acevents.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#include "acevents.h"
#ifdef ACPI_ASL_COMPILER
#include <acpi/acdisasm.h>
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/acpica/dswscope.c
index 9e6073265873..908645e72f03 100644
--- a/drivers/acpi/dispatcher/dswscope.c
+++ b/drivers/acpi/acpica/dswscope.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acdispat.h>
+#include "accommon.h"
+#include "acdispat.h"
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dswscope")
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/acpica/dswstate.c
index b00d4af791aa..40f92bf7dce5 100644
--- a/drivers/acpi/dispatcher/dswstate.c
+++ b/drivers/acpi/acpica/dswstate.c
@@ -42,9 +42,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/acdispat.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "acdispat.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dswstate")
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/acpica/evevent.c
index c56c5c6ea77b..803edd9e3f6a 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acevents.h>
+#include "accommon.h"
+#include "acevents.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evevent")
@@ -72,8 +73,8 @@ acpi_status acpi_ev_initialize_events(void)
/*
* Initialize the Fixed and General Purpose Events. This is done prior to
- * enabling SCIs to prevent interrupts from occurring before the handlers are
- * installed.
+ * enabling SCIs to prevent interrupts from occurring before the handlers
+ * are installed.
*/
status = acpi_ev_fixed_event_initialize();
if (ACPI_FAILURE(status)) {
@@ -192,8 +193,8 @@ static acpi_status acpi_ev_fixed_event_initialize(void)
acpi_status status;
/*
- * Initialize the structure that keeps track of fixed event handlers
- * and enable the fixed events.
+ * Initialize the structure that keeps track of fixed event handlers and
+ * enable the fixed events.
*/
for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
acpi_gbl_fixed_event_handlers[i].handler = NULL;
@@ -237,7 +238,7 @@ u32 acpi_ev_fixed_event_detect(void)
/*
* Read the fixed feature status and enable registers, as all the cases
- * depend on their values. Ignore errors here.
+ * depend on their values. Ignore errors here.
*/
(void)acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status);
(void)acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable);
@@ -291,8 +292,8 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event)
status_register_id, 1);
/*
- * Make sure we've got a handler. If not, report an error.
- * The event is disabled to prevent further interrupts.
+ * Make sure we've got a handler. If not, report an error. The event is
+ * disabled to prevent further interrupts.
*/
if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
(void)acpi_set_register(acpi_gbl_fixed_event_info[event].
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/acpica/evgpe.c
index f45c74fe745e..f345ced36477 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acevents.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evgpe")
@@ -125,7 +126,7 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
(1 <<
(gpe_event_info->gpe_number - gpe_register_info->base_gpe_number));
- /* 1) Disable case. Simply clear all enable bits */
+ /* 1) Disable case. Simply clear all enable bits */
if (type == ACPI_GPE_DISABLE) {
ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
@@ -134,7 +135,7 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
return_ACPI_STATUS(AE_OK);
}
- /* 2) Enable case. Set/Clear the appropriate enable bits */
+ /* 2) Enable case. Set/Clear the appropriate enable bits */
switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
case ACPI_GPE_TYPE_WAKE:
@@ -295,7 +296,7 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
*
* FUNCTION: acpi_ev_get_gpe_event_info
*
- * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1
+ * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1
* gpe_number - Raw GPE number
*
* RETURN: A GPE event_info struct. NULL if not a valid GPE
@@ -372,7 +373,7 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device,
*
* RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
*
- * DESCRIPTION: Detect if any GP events have occurred. This function is
+ * DESCRIPTION: Detect if any GP events have occurred. This function is
* executed at interrupt level.
*
******************************************************************************/
@@ -400,8 +401,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
/*
* We need to obtain the GPE lock for both the data structs and registers
- * Note: Not necessary to obtain the hardware lock, since the GPE registers
- * are owned by the gpe_lock.
+ * Note: Not necessary to obtain the hardware lock, since the GPE
+ * registers are owned by the gpe_lock.
*/
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
@@ -410,9 +411,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
gpe_block = gpe_xrupt_list->gpe_block_list_head;
while (gpe_block) {
/*
- * Read all of the 8-bit GPE status and enable registers
- * in this GPE block, saving all of them.
- * Find all currently active GP events.
+ * Read all of the 8-bit GPE status and enable registers in this GPE
+ * block, saving all of them. Find all currently active GP events.
*/
for (i = 0; i < gpe_block->register_count; i++) {
@@ -423,10 +423,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
/* Read the Status Register */
status =
- acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH,
- &status_reg,
- &gpe_register_info->
- status_address);
+ acpi_read(&status_reg,
+ &gpe_register_info->status_address);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -434,10 +432,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
/* Read the Enable Register */
status =
- acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH,
- &enable_reg,
- &gpe_register_info->
- enable_address);
+ acpi_read(&enable_reg,
+ &gpe_register_info->enable_address);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -527,8 +523,8 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
(void)acpi_ev_enable_gpe(gpe_event_info, FALSE);
/*
- * Take a snapshot of the GPE info for this level - we copy the
- * info to prevent a race condition with remove_handler/remove_block.
+ * Take a snapshot of the GPE info for this level - we copy the info to
+ * prevent a race condition with remove_handler/remove_block.
*/
ACPI_MEMCPY(&local_gpe_event_info, gpe_event_info,
sizeof(struct acpi_gpe_event_info));
@@ -539,8 +535,8 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
}
/*
- * Must check for control method type dispatch one more
- * time to avoid race with ev_gpe_install_handler
+ * Must check for control method type dispatch one more time to avoid a
+ * race with ev_gpe_install_handler
*/
if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) ==
ACPI_GPE_DISPATCH_METHOD) {
@@ -584,8 +580,8 @@ static void acpi_ev_asynch_enable_gpe(void *context)
if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
ACPI_GPE_LEVEL_TRIGGERED) {
/*
- * GPE is level-triggered, we clear the GPE status bit after
- * handling the event.
+ * GPE is level-triggered, we clear the GPE status bit after handling
+ * the event.
*/
status = acpi_hw_clear_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
@@ -624,7 +620,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
acpi_os_gpe_count(gpe_number);
/*
- * If edge-triggered, clear the GPE status bit now. Note that
+ * If edge-triggered, clear the GPE status bit now. Note that
* level-triggered events are cleared after the GPE is serviced.
*/
if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
@@ -650,7 +646,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
/*
* Invoke the installed handler (at interrupt level)
- * Ignore return status for now. TBD: leave GPE disabled on error?
+ * Ignore return status for now.
+ * TBD: leave GPE disabled on error?
*/
(void)gpe_event_info->dispatch.handler->address(gpe_event_info->
dispatch.
@@ -708,7 +705,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
gpe_number));
/*
- * Disable the GPE. The GPE will remain disabled until the ACPI
+ * Disable the GPE. The GPE will remain disabled until the ACPICA
* Core Subsystem is restarted, or a handler is installed.
*/
status = acpi_ev_disable_gpe(gpe_event_info);
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index 73c058e2f5c2..484cc0565d5b 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acevents.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evgpeblk")
@@ -124,6 +125,7 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info)
* FUNCTION: acpi_ev_walk_gpe_list
*
* PARAMETERS: gpe_walk_callback - Routine called for each GPE block
+ * Context - Value passed to callback
*
* RETURN: Status
*
@@ -131,7 +133,8 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info)
*
******************************************************************************/
-acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback)
+acpi_status
+acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context)
{
struct acpi_gpe_block_info *gpe_block;
struct acpi_gpe_xrupt_info *gpe_xrupt_info;
@@ -154,8 +157,13 @@ acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback)
/* One callback per GPE block */
- status = gpe_walk_callback(gpe_xrupt_info, gpe_block);
+ status =
+ gpe_walk_callback(gpe_xrupt_info, gpe_block,
+ context);
if (ACPI_FAILURE(status)) {
+ if (status == AE_CTRL_END) { /* Callback abort */
+ status = AE_OK;
+ }
goto unlock_and_exit;
}
@@ -186,7 +194,8 @@ acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback)
acpi_status
acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
- struct acpi_gpe_block_info *gpe_block)
+ struct acpi_gpe_block_info *gpe_block,
+ void *context)
{
struct acpi_gpe_event_info *gpe_event_info;
u32 i;
@@ -309,17 +318,17 @@ acpi_ev_save_method_info(acpi_handle obj_handle,
(gpe_block->block_base_number +
(gpe_block->register_count * 8)))) {
/*
- * Not valid for this GPE block, just ignore it
- * However, it may be valid for a different GPE block, since GPE0 and GPE1
- * methods both appear under \_GPE.
+ * Not valid for this GPE block, just ignore it. However, it may be
+ * valid for a different GPE block, since GPE0 and GPE1 methods both
+ * appear under \_GPE.
*/
return_ACPI_STATUS(AE_OK);
}
/*
- * Now we can add this information to the gpe_event_info block
- * for use during dispatch of this GPE. Default type is RUNTIME, although
- * this may change when the _PRW methods are executed later.
+ * Now we can add this information to the gpe_event_info block for use
+ * during dispatch of this GPE. Default type is RUNTIME, although this may
+ * change when the _PRW methods are executed later.
*/
gpe_event_info =
&gpe_block->event_info[gpe_number - gpe_block->block_base_number];
@@ -394,8 +403,8 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
gpe_block = gpe_info->gpe_block;
/*
- * The _PRW object must return a package, we are only interested
- * in the first element
+ * The _PRW object must return a package, we are only interested in the
+ * first element
*/
obj_desc = pkg_desc->package.elements[0];
@@ -434,7 +443,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
/*
* Is this GPE within this block?
*
- * TRUE iff these conditions are true:
+ * TRUE if and only if these conditions are true:
* 1) The GPE devices match.
* 2) The GPE index(number) is within the range of the Gpe Block
* associated with the GPE device.
@@ -457,6 +466,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
if (ACPI_FAILURE(status)) {
goto cleanup;
}
+
status =
acpi_ev_update_gpe_enable_masks(gpe_event_info,
ACPI_GPE_DISABLE);
@@ -476,9 +486,9 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
* RETURN: A GPE interrupt block
*
* DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt
- * block per unique interrupt level used for GPEs.
- * Should be called only when the GPE lists are semaphore locked
- * and not subject to change.
+ * block per unique interrupt level used for GPEs. Should be
+ * called only when the GPE lists are semaphore locked and not
+ * subject to change.
*
******************************************************************************/
@@ -608,8 +618,9 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
*
* FUNCTION: acpi_ev_install_gpe_block
*
- * PARAMETERS: gpe_block - New GPE block
- * interrupt_number - Xrupt to be associated with this GPE block
+ * PARAMETERS: gpe_block - New GPE block
+ * interrupt_number - Xrupt to be associated with this
+ * GPE block
*
* RETURN: Status
*
@@ -666,7 +677,7 @@ acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block,
*
* FUNCTION: acpi_ev_delete_gpe_block
*
- * PARAMETERS: gpe_block - Existing GPE block
+ * PARAMETERS: gpe_block - Existing GPE block
*
* RETURN: Status
*
@@ -688,7 +699,8 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block)
/* Disable all GPEs in this block */
- status = acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block);
+ status =
+ acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL);
if (!gpe_block->previous && !gpe_block->next) {
@@ -715,6 +727,9 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block)
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
}
+ acpi_current_gpe_count -=
+ gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH;
+
/* Free the gpe_block */
ACPI_FREE(gpe_block->register_info);
@@ -786,9 +801,9 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
/*
* Initialize the GPE Register and Event structures. A goal of these
- * tables is to hide the fact that there are two separate GPE register sets
- * in a given GPE hardware block, the status registers occupy the first half,
- * and the enable registers occupy the second half.
+ * tables is to hide the fact that there are two separate GPE register
+ * sets in a given GPE hardware block, the status registers occupy the
+ * first half, and the enable registers occupy the second half.
*/
this_register = gpe_register_info;
this_event = gpe_event_info;
@@ -816,10 +831,8 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
ACPI_GPE_REGISTER_WIDTH;
this_register->enable_address.bit_width =
ACPI_GPE_REGISTER_WIDTH;
- this_register->status_address.bit_offset =
- ACPI_GPE_REGISTER_WIDTH;
- this_register->enable_address.bit_offset =
- ACPI_GPE_REGISTER_WIDTH;
+ this_register->status_address.bit_offset = 0;
+ this_register->enable_address.bit_offset = 0;
/* Init the event_info for each GPE within this register */
@@ -832,18 +845,14 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
/* Disable all GPEs within this register */
- status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, 0x00,
- &this_register->
- enable_address);
+ status = acpi_write(0x00, &this_register->enable_address);
if (ACPI_FAILURE(status)) {
goto error_exit;
}
/* Clear any pending GPE events within this register */
- status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, 0xFF,
- &this_register->
- status_address);
+ status = acpi_write(0xFF, &this_register->status_address);
if (ACPI_FAILURE(status)) {
goto error_exit;
}
@@ -956,6 +965,9 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
gpe_device->name.ascii, gpe_block->register_count,
interrupt_number));
+ /* Update global count of currently available GPEs */
+
+ acpi_current_gpe_count += register_count * ACPI_GPE_REGISTER_WIDTH;
return_ACPI_STATUS(AE_OK);
}
@@ -1055,7 +1067,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device,
/* Enable all valid runtime GPEs found above */
- status = acpi_hw_enable_runtime_gpe_block(NULL, gpe_block);
+ status = acpi_hw_enable_runtime_gpe_block(NULL, gpe_block, NULL);
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO, "Could not enable GPEs in GpeBlock %p",
gpe_block));
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/acpica/evmisc.c
index 1d5670be729a..5f893057bcc6 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -42,18 +42,15 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acevents.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acnamesp.h"
+#include "acinterp.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evmisc")
-/* Pointer to FACS needed for the Global Lock */
-static struct acpi_table_facs *facs = NULL;
-
/* Local prototypes */
-
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
static u32 acpi_ev_global_lock_handler(void *context);
@@ -152,7 +149,9 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
break;
default:
+
/* All other types are not supported */
+
return (AE_TYPE);
}
}
@@ -193,9 +192,8 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
acpi_ut_delete_generic_state(notify_info);
}
} else {
- /*
- * There is no notify handler (per-device or system) for this device.
- */
+ /* There is no notify handler (per-device or system) for this device */
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No notify handler for Notify (%4.4s, %X) node %p\n",
acpi_ut_get_node_name(node), notify_value,
@@ -229,9 +227,8 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
ACPI_FUNCTION_ENTRY();
/*
- * We will invoke a global notify handler if installed.
- * This is done _before_ we invoke the per-device handler attached
- * to the device.
+ * We will invoke a global notify handler if installed. This is done
+ * _before_ we invoke the per-device handler attached to the device.
*/
if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {
@@ -299,7 +296,7 @@ static u32 acpi_ev_global_lock_handler(void *context)
* If we don't get it now, it will be marked pending and we will
* take another interrupt when it becomes free.
*/
- ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
+ ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
if (acquired) {
/* Got the lock, now wake all threads waiting for it */
@@ -336,34 +333,27 @@ acpi_status acpi_ev_init_global_lock_handler(void)
ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
- status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
- ACPI_CAST_INDIRECT_PTR(struct
- acpi_table_header,
- &facs));
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ /* Attempt installation of the global lock handler */
- acpi_gbl_global_lock_present = TRUE;
status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
acpi_ev_global_lock_handler,
NULL);
/*
- * If the global lock does not exist on this platform, the attempt
- * to enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick)
- * Map to AE_OK, but mark global lock as not present.
- * Any attempt to actually use the global lock will be flagged
- * with an error.
+ * If the global lock does not exist on this platform, the attempt to
+ * enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick).
+ * Map to AE_OK, but mark global lock as not present. Any attempt to
+ * actually use the global lock will be flagged with an error.
*/
if (status == AE_NO_HARDWARE_RESPONSE) {
ACPI_ERROR((AE_INFO,
"No response from Global Lock hardware, disabling lock"));
acpi_gbl_global_lock_present = FALSE;
- status = AE_OK;
+ return_ACPI_STATUS(AE_OK);
}
+ acpi_gbl_global_lock_present = TRUE;
return_ACPI_STATUS(status);
}
@@ -462,8 +452,8 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
}
/*
- * Make sure that a global lock actually exists. If not, just treat
- * the lock as a standard mutex.
+ * Make sure that a global lock actually exists. If not, just treat the
+ * lock as a standard mutex.
*/
if (!acpi_gbl_global_lock_present) {
acpi_gbl_global_lock_acquired = TRUE;
@@ -472,7 +462,7 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
/* Attempt to acquire the actual hardware lock */
- ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
+ ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
if (acquired) {
/* We got the lock */
@@ -536,7 +526,7 @@ acpi_status acpi_ev_release_global_lock(void)
/* Allow any thread to release the lock */
- ACPI_RELEASE_GLOBAL_LOCK(facs, pending);
+ ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending);
/*
* If the pending bit was set, we must write GBL_RLS to the control
@@ -582,8 +572,8 @@ void acpi_ev_terminate(void)
if (acpi_gbl_events_initialized) {
/*
- * Disable all event-related functionality.
- * In all cases, on error, print a message but obviously we don't abort.
+ * Disable all event-related functionality. In all cases, on error,
+ * print a message but obviously we don't abort.
*/
/* Disable all fixed events */
@@ -599,7 +589,7 @@ void acpi_ev_terminate(void)
/* Disable all GPEs in all GPE blocks */
- status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block);
+ status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL);
/* Remove SCI handler */
@@ -617,7 +607,7 @@ void acpi_ev_terminate(void)
/* Deallocate all handler objects installed within GPE info structs */
- status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers);
+ status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers, NULL);
/* Return to original mode if necessary */
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/acpica/evregion.c
index 236fbd1ca438..665c0887ab4d 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -42,22 +42,15 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acevents.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acnamesp.h"
+#include "acinterp.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evregion")
-#define ACPI_NUM_DEFAULT_SPACES 4
-static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = {
- ACPI_ADR_SPACE_SYSTEM_MEMORY,
- ACPI_ADR_SPACE_SYSTEM_IO,
- ACPI_ADR_SPACE_PCI_CONFIG,
- ACPI_ADR_SPACE_DATA_TABLE
-};
/* Local prototypes */
-
static acpi_status
acpi_ev_reg_run(acpi_handle obj_handle,
u32 level, void *context, void **return_value);
@@ -66,6 +59,17 @@ static acpi_status
acpi_ev_install_handler(acpi_handle obj_handle,
u32 level, void *context, void **return_value);
+/* These are the address spaces that will get default handlers */
+
+#define ACPI_NUM_DEFAULT_SPACES 4
+
+static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = {
+ ACPI_ADR_SPACE_SYSTEM_MEMORY,
+ ACPI_ADR_SPACE_SYSTEM_IO,
+ ACPI_ADR_SPACE_PCI_CONFIG,
+ ACPI_ADR_SPACE_DATA_TABLE
+};
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_install_region_handlers
@@ -91,18 +95,19 @@ acpi_status acpi_ev_install_region_handlers(void)
}
/*
- * All address spaces (PCI Config, EC, SMBus) are scope dependent
- * and registration must occur for a specific device.
+ * All address spaces (PCI Config, EC, SMBus) are scope dependent and
+ * registration must occur for a specific device.
*
- * In the case of the system memory and IO address spaces there is currently
- * no device associated with the address space. For these we use the root.
+ * In the case of the system memory and IO address spaces there is
+ * currently no device associated with the address space. For these we
+ * use the root.
*
- * We install the default PCI config space handler at the root so
- * that this space is immediately available even though the we have
- * not enumerated all the PCI Root Buses yet. This is to conform
- * to the ACPI specification which states that the PCI config
- * space must be always available -- even though we are nowhere
- * near ready to find the PCI root buses at this point.
+ * We install the default PCI config space handler at the root so that
+ * this space is immediately available even though the we have not
+ * enumerated all the PCI Root Buses yet. This is to conform to the ACPI
+ * specification which states that the PCI config space must be always
+ * available -- even though we are nowhere near ready to find the PCI root
+ * buses at this point.
*
* NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler
* has already been installed (via acpi_install_address_space_handler).
@@ -160,12 +165,11 @@ acpi_status acpi_ev_initialize_op_regions(void)
return_ACPI_STATUS(status);
}
- /*
- * Run the _REG methods for op_regions in each default address space
- */
- for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
+ /* Run the _REG methods for op_regions in each default address space */
- /* TBD: Make sure handler is the DEFAULT handler, otherwise
+ for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
+ /*
+ * TBD: Make sure handler is the DEFAULT handler, otherwise
* _REG will have already been run.
*/
status = acpi_ev_execute_reg_methods(acpi_gbl_root_node,
@@ -318,13 +322,13 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
}
/*
- * It may be the case that the region has never been initialized
+ * It may be the case that the region has never been initialized.
* Some types of regions require special init code
*/
if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) {
- /*
- * This region has not been initialized yet, do it
- */
+
+ /* This region has not been initialized yet, do it */
+
region_setup = handler_desc->address_space.setup;
if (!region_setup) {
@@ -339,9 +343,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
}
/*
- * We must exit the interpreter because the region
- * setup will potentially execute control methods
- * (e.g., _REG method for this region)
+ * We must exit the interpreter because the region setup will
+ * potentially execute control methods (for example, the _REG method
+ * for this region)
*/
acpi_ex_exit_interpreter();
@@ -364,9 +368,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
return_ACPI_STATUS(status);
}
- /*
- * Region initialization may have been completed by region_setup
- */
+ /* Region initialization may have been completed by region_setup */
+
if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) {
region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE;
@@ -521,8 +524,8 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
}
/*
- * If the region has been activated, call the setup handler
- * with the deactivate notification
+ * If the region has been activated, call the setup handler with
+ * the deactivate notification
*/
if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) {
region_setup = handler_obj->address_space.setup;
@@ -668,8 +671,8 @@ acpi_ev_install_handler(acpi_handle obj_handle,
}
/*
- * We only care about regions.and objects
- * that are allowed to have address space handlers
+ * We only care about regions and objects that are allowed to have
+ * address space handlers
*/
if ((node->type != ACPI_TYPE_DEVICE) &&
(node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) {
@@ -710,9 +713,9 @@ acpi_ev_install_handler(acpi_handle obj_handle,
/*
* Since the object we found it on was a device, then it
* means that someone has already installed a handler for
- * the branch of the namespace from this device on. Just
+ * the branch of the namespace from this device on. Just
* bail out telling the walk routine to not traverse this
- * branch. This preserves the scoping rule for handlers.
+ * branch. This preserves the scoping rule for handlers.
*/
return (AE_CTRL_DEPTH);
}
@@ -723,9 +726,8 @@ acpi_ev_install_handler(acpi_handle obj_handle,
}
/*
- * As long as the device didn't have a handler for this
- * space we don't care about it. We just ignore it and
- * proceed.
+ * As long as the device didn't have a handler for this space we
+ * don't care about it. We just ignore it and proceed.
*/
return (AE_OK);
}
@@ -733,16 +735,14 @@ acpi_ev_install_handler(acpi_handle obj_handle,
/* Object is a Region */
if (obj_desc->region.space_id != handler_obj->address_space.space_id) {
- /*
- * This region is for a different address space
- * -- just ignore it
- */
+
+ /* This region is for a different address space, just ignore it */
+
return (AE_OK);
}
/*
- * Now we have a region and it is for the handler's address
- * space type.
+ * Now we have a region and it is for the handler's address space type.
*
* First disconnect region for any previous handler (if any)
*/
@@ -786,9 +786,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node,
ACPI_FUNCTION_TRACE(ev_install_space_handler);
/*
- * This registration is valid for only the types below
- * and the root. This is where the default handlers
- * get placed.
+ * This registration is valid for only the types below and the root. This
+ * is where the default handlers get placed.
*/
if ((node->type != ACPI_TYPE_DEVICE) &&
(node->type != ACPI_TYPE_PROCESSOR) &&
@@ -848,8 +847,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node,
obj_desc = acpi_ns_get_attached_object(node);
if (obj_desc) {
/*
- * The attached device object already exists.
- * Make sure the handler is not already installed.
+ * The attached device object already exists. Make sure the handler
+ * is not already installed.
*/
handler_obj = obj_desc->device.handler;
@@ -864,8 +863,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node,
handler) {
/*
* It is (relatively) OK to attempt to install the SAME
- * handler twice. This can easily happen
- * with PCI_Config space.
+ * handler twice. This can easily happen with the
+ * PCI_Config space.
*/
status = AE_SAME_HANDLER;
goto unlock_and_exit;
@@ -925,9 +924,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node,
/*
* Install the handler
*
- * At this point there is no existing handler.
- * Just allocate the object for the handler and link it
- * into the list.
+ * At this point there is no existing handler. Just allocate the object
+ * for the handler and link it into the list.
*/
handler_obj =
acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_ADDRESS_HANDLER);
@@ -1000,11 +998,10 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
ACPI_FUNCTION_TRACE(ev_execute_reg_methods);
/*
- * Run all _REG methods for all Operation Regions for this
- * space ID. This is a separate walk in order to handle any
- * interdependencies between regions and _REG methods. (i.e. handlers
- * must be installed for all regions of this Space ID before we
- * can run any _REG methods)
+ * Run all _REG methods for all Operation Regions for this space ID. This
+ * is a separate walk in order to handle any interdependencies between
+ * regions and _REG methods. (i.e. handlers must be installed for all
+ * regions of this Space ID before we can run any _REG methods)
*/
status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run,
@@ -1042,8 +1039,8 @@ acpi_ev_reg_run(acpi_handle obj_handle,
}
/*
- * We only care about regions.and objects
- * that are allowed to have address space handlers
+ * We only care about regions.and objects that are allowed to have address
+ * space handlers
*/
if ((node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) {
return (AE_OK);
@@ -1062,10 +1059,9 @@ acpi_ev_reg_run(acpi_handle obj_handle,
/* Object is a Region */
if (obj_desc->region.space_id != space_id) {
- /*
- * This region is for a different address space
- * -- just ignore it
- */
+
+ /* This region is for a different address space, just ignore it */
+
return (AE_OK);
}
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 6b94b38df07d..f3f1fb45c3dc 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acevents.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evrgnini")
@@ -233,9 +234,9 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
if (ACPI_FAILURE(status)) {
if (status == AE_SAME_HANDLER) {
/*
- * It is OK if the handler is already installed on the root
- * bridge. Still need to return a context object for the
- * new PCI_Config operation region, however.
+ * It is OK if the handler is already installed on the
+ * root bridge. Still need to return a context object
+ * for the new PCI_Config operation region, however.
*/
status = AE_OK;
} else {
@@ -272,8 +273,8 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
}
/*
- * For PCI_Config space access, we need the segment, bus,
- * device and function numbers. Acquire them here.
+ * For PCI_Config space access, we need the segment, bus, device and
+ * function numbers. Acquire them here.
*
* Find the parent device object. (This allows the operation region to be
* within a subscope under the device, such as a control method.)
@@ -289,16 +290,16 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
}
/*
- * Get the PCI device and function numbers from the _ADR object
- * contained in the parent's scope.
+ * Get the PCI device and function numbers from the _ADR object contained
+ * in the parent's scope.
*/
status =
acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, pci_device_node,
&pci_value);
/*
- * The default is zero, and since the allocation above zeroed
- * the data, just do nothing on failure.
+ * The default is zero, and since the allocation above zeroed the data,
+ * just do nothing on failure.
*/
if (ACPI_SUCCESS(status)) {
pci_id->device = ACPI_HIWORD(ACPI_LODWORD(pci_value));
@@ -382,9 +383,8 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
struct acpi_compatible_id_list *cid;
u32 i;
- /*
- * Get the _HID and check for a PCI Root Bridge
- */
+ /* Get the _HID and check for a PCI Root Bridge */
+
status = acpi_ut_execute_HID(node, &hid);
if (ACPI_FAILURE(status)) {
return (FALSE);
@@ -394,10 +394,8 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
return (TRUE);
}
- /*
- * The _HID did not match.
- * Get the _CID and check for a PCI Root Bridge
- */
+ /* The _HID did not match. Get the _CID and check for a PCI Root Bridge */
+
status = acpi_ut_execute_CID(node, &cid);
if (ACPI_FAILURE(status)) {
return (FALSE);
@@ -516,9 +514,9 @@ acpi_ev_default_region_setup(acpi_handle handle,
* Get the appropriate address space handler for a newly
* created region.
*
- * This also performs address space specific initialization. For
+ * This also performs address space specific initialization. For
* example, PCI regions must have an _ADR object that contains
- * a PCI address in the scope of the definition. This address is
+ * a PCI address in the scope of the definition. This address is
* required to perform an access to PCI config space.
*
* MUTEX: Interpreter should be unlocked, because we may run the _REG
@@ -572,7 +570,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
if (ACPI_SUCCESS(status)) {
/*
* The _REG method is optional and there can be only one per region
- * definition. This will be executed when the handler is attached
+ * definition. This will be executed when the handler is attached
* or removed
*/
region_obj2->extra.method_REG = method_node;
@@ -670,10 +668,8 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
}
}
- /*
- * This node does not have the handler we need;
- * Pop up one level
- */
+ /* This node does not have the handler we need; Pop up one level */
+
node = acpi_ns_get_parent_node(node);
}
diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/acpica/evsci.c
index 2a8b77877610..567b356c85af 100644
--- a/drivers/acpi/events/evsci.c
+++ b/drivers/acpi/acpica/evsci.c
@@ -43,7 +43,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acevents.h>
+#include "accommon.h"
+#include "acevents.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evsci")
@@ -115,10 +116,8 @@ u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context)
* if this interrupt handler is installed, ACPI is enabled.
*/
- /*
- * GPEs:
- * Check for and dispatch any GPEs that have occurred
- */
+ /* GPEs: Check for and dispatch any GPEs that have occurred */
+
interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
return_UINT32(interrupt_handled);
@@ -158,11 +157,11 @@ u32 acpi_ev_install_sci_handler(void)
* RETURN: E_OK if handler uninstalled OK, E_ERROR if handler was not
* installed to begin with
*
- * DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be
+ * DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be
* taken.
*
* Note: It doesn't seem important to disable all events or set the event
- * enable registers to their original values. The OS should disable
+ * enable registers to their original values. The OS should disable
* the SCI interrupt level when the handler is removed, so no more
* events will come in.
*
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/acpica/evxface.c
index 94a6efe020be..3aca9010a11e 100644
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -42,9 +42,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acevents.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acevents.h"
+#include "acinterp.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evxface")
@@ -267,7 +268,7 @@ acpi_install_notify_handler(acpi_handle device,
/*
* Root Object:
* Registering a notify handler on the root object indicates that the
- * caller wishes to receive notifications for all objects. Note that
+ * caller wishes to receive notifications for all objects. Note that
* only one <external> global handler can be regsitered (per notify type).
*/
if (device == ACPI_ROOT_OBJECT) {
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index 41554f736b68..35485e4b60a6 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -42,13 +42,19 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acevents.h>
-#include <acpi/acnamesp.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acnamesp.h"
+#include "actables.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evxfevnt")
+/* Local prototypes */
+acpi_status
+acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block, void *context);
+
/*******************************************************************************
*
* FUNCTION: acpi_enable
@@ -60,6 +66,7 @@ ACPI_MODULE_NAME("evxfevnt")
* DESCRIPTION: Transfers the system into ACPI mode.
*
******************************************************************************/
+
acpi_status acpi_enable(void)
{
acpi_status status = AE_OK;
@@ -161,8 +168,8 @@ acpi_status acpi_enable_event(u32 event, u32 flags)
}
/*
- * Enable the requested fixed event (by writing a one to the
- * enable register bit)
+ * Enable the requested fixed event (by writing a one to the enable
+ * register bit)
*/
status =
acpi_set_register(acpi_gbl_fixed_event_info[event].
@@ -343,8 +350,8 @@ acpi_status acpi_disable_event(u32 event, u32 flags)
}
/*
- * Disable the requested fixed event (by writing a zero to the
- * enable register bit)
+ * Disable the requested fixed event (by writing a zero to the enable
+ * register bit)
*/
status =
acpi_set_register(acpi_gbl_fixed_event_info[event].
@@ -396,8 +403,8 @@ acpi_status acpi_clear_event(u32 event)
}
/*
- * Clear the requested fixed event (By writing a one to the
- * status register bit)
+ * Clear the requested fixed event (By writing a one to the status
+ * register bit)
*/
status =
acpi_set_register(acpi_gbl_fixed_event_info[event].
@@ -717,3 +724,148 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)
}
ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_gpe_device
+ *
+ * PARAMETERS: Index - System GPE index (0-current_gpe_count)
+ * gpe_device - Where the parent GPE Device is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL
+ * gpe device indicates that the gpe number is contained in one of
+ * the FADT-defined gpe blocks. Otherwise, the GPE block device.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_get_gpe_device(u32 index, acpi_handle *gpe_device)
+{
+ struct acpi_gpe_device_info info;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_get_gpe_device);
+
+ if (!gpe_device) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ if (index >= acpi_current_gpe_count) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ /* Setup and walk the GPE list */
+
+ info.index = index;
+ info.status = AE_NOT_EXIST;
+ info.gpe_device = NULL;
+ info.next_block_base_index = 0;
+
+ status = acpi_ev_walk_gpe_list(acpi_ev_get_gpe_device, &info);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ *gpe_device = info.gpe_device;
+ return_ACPI_STATUS(info.status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_get_gpe_device)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_get_gpe_device
+ *
+ * PARAMETERS: GPE_WALK_CALLBACK
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE
+ * block device. NULL if the GPE is one of the FADT-defined GPEs.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block, void *context)
+{
+ struct acpi_gpe_device_info *info = context;
+
+ /* Increment Index by the number of GPEs in this block */
+
+ info->next_block_base_index +=
+ (gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH);
+
+ if (info->index < info->next_block_base_index) {
+ /*
+ * The GPE index is within this block, get the node. Leave the node
+ * NULL for the FADT-defined GPEs
+ */
+ if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) {
+ info->gpe_device = gpe_block->node;
+ }
+
+ info->status = AE_OK;
+ return (AE_CTRL_END);
+ }
+
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_disable_all_gpes
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
+ *
+ ******************************************************************************/
+
+acpi_status acpi_disable_all_gpes(void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_disable_all_gpes);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_hw_disable_all_gpes();
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+ return_ACPI_STATUS(status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_enable_all_runtime_gpes
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
+ *
+ ******************************************************************************/
+
+acpi_status acpi_enable_all_runtime_gpes(void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_enable_all_runtime_gpes);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_hw_enable_all_runtime_gpes();
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/acpica/evxfregn.c
index e8750807e57d..479e7a3721be 100644
--- a/drivers/acpi/events/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -43,8 +43,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acevents.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acevents.h"
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evxfregn")
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 74da6fa52ef1..932bbc26aa04 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -42,10 +42,11 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/acnamesp.h>
-#include <acpi/actables.h>
-#include <acpi/acdispat.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#include "actables.h"
+#include "acdispat.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exconfig")
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/acpica/exconvrt.c
index 1d1f35adddde..0be10188316e 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/acpica/exconvrt.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/amlcode.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exconvrt")
diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/acpica/excreate.c
index ad09696d5069..a57ad2564ab0 100644
--- a/drivers/acpi/executer/excreate.c
+++ b/drivers/acpi/acpica/excreate.c
@@ -42,9 +42,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/amlcode.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "amlcode.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("excreate")
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/acpica/exdump.c
index d087a7d28aa5..aa313574b0df 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -42,9 +42,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/amlcode.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "amlcode.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exdump")
diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/acpica/exfield.c
index 3e440d84226a..a352d0233857 100644
--- a/drivers/acpi/executer/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acdispat.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acdispat.h"
+#include "acinterp.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exfield")
diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/acpica/exfldio.c
index 9ff9d1f4615d..ef58ac4e687b 100644
--- a/drivers/acpi/executer/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -42,10 +42,11 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/amlcode.h>
-#include <acpi/acevents.h>
-#include <acpi/acdispat.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "amlcode.h"
+#include "acevents.h"
+#include "acdispat.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exfldio")
@@ -498,14 +499,13 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(status);
}
- ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "I/O to Data Register: ValuePtr %p\n",
- value));
-
if (read_write == ACPI_READ) {
/* Read the datum from the data_register */
+ ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
+ "Read from Data Register\n"));
+
status =
acpi_ex_extract_from_field(obj_desc->index_field.
data_obj, value,
@@ -513,6 +513,10 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
} else {
/* Write the datum to the data_register */
+ ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
+ "Write to Data Register: Value %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64(*value)));
+
status =
acpi_ex_insert_into_field(obj_desc->index_field.
data_obj, value,
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/acpica/exmisc.c
index efb191340059..6b0747ac683b 100644
--- a/drivers/acpi/executer/exmisc.c
+++ b/drivers/acpi/acpica/exmisc.c
@@ -43,9 +43,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/amlcode.h>
-#include <acpi/amlresrc.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "amlcode.h"
+#include "amlresrc.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exmisc")
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/acpica/exmutex.c
index a8bf3d713e28..d301c1f363ef 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/acpica/exmutex.c
@@ -43,8 +43,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/acevents.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "acevents.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exmutex")
diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/acpica/exnames.c
index 817e67be3697..ffdae122d94a 100644
--- a/drivers/acpi/executer/exnames.c
+++ b/drivers/acpi/acpica/exnames.c
@@ -43,8 +43,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/amlcode.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exnames")
diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/acpica/exoparg1.c
index f622f9eac8a1..b530480cc7d5 100644
--- a/drivers/acpi/executer/exoparg1.c
+++ b/drivers/acpi/acpica/exoparg1.c
@@ -43,11 +43,12 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/acdispat.h>
-#include <acpi/acinterp.h>
-#include <acpi/amlcode.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "amlcode.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exoparg1")
diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/acpica/exoparg2.c
index 368def5dffce..0b4f513ca885 100644
--- a/drivers/acpi/executer/exoparg2.c
+++ b/drivers/acpi/acpica/exoparg2.c
@@ -42,10 +42,11 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/acinterp.h>
-#include <acpi/acevents.h>
-#include <acpi/amlcode.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "acinterp.h"
+#include "acevents.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exoparg2")
diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/acpica/exoparg3.c
index 9cb4197681af..c6520bbf882b 100644
--- a/drivers/acpi/executer/exoparg3.c
+++ b/drivers/acpi/acpica/exoparg3.c
@@ -43,9 +43,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/acparser.h>
-#include <acpi/amlcode.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "acparser.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exoparg3")
diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/acpica/exoparg6.c
index 67d48737af53..ae43f7670a6c 100644
--- a/drivers/acpi/executer/exoparg6.c
+++ b/drivers/acpi/acpica/exoparg6.c
@@ -43,9 +43,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/acparser.h>
-#include <acpi/amlcode.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "acparser.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exoparg6")
diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/acpica/exprep.c
index 5d438c32989d..a226f74d4a5c 100644
--- a/drivers/acpi/executer/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -43,9 +43,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/amlcode.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "amlcode.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exprep")
@@ -404,7 +405,7 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
*
* RETURN: Status
*
- * DESCRIPTION: Construct an union acpi_operand_object of type def_field and
+ * DESCRIPTION: Construct a union acpi_operand_object of type def_field and
* connect it to the parent Node.
*
******************************************************************************/
diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/acpica/exregion.c
index 7a41c409ae4d..76ec8ff903b8 100644
--- a/drivers/acpi/executer/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -43,7 +43,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acinterp.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exregion")
diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/acpica/exresnte.c
index 423ad3635f3d..a063a74006f6 100644
--- a/drivers/acpi/executer/exresnte.c
+++ b/drivers/acpi/acpica/exresnte.c
@@ -43,9 +43,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acdispat.h>
-#include <acpi/acinterp.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exresnte")
diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/acpica/exresolv.c
index 89571b92a522..f6105a6d6126 100644
--- a/drivers/acpi/executer/exresolv.c
+++ b/drivers/acpi/acpica/exresolv.c
@@ -43,10 +43,11 @@
*/
#include <acpi/acpi.h>
-#include <acpi/amlcode.h>
-#include <acpi/acdispat.h>
-#include <acpi/acinterp.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exresolv")
@@ -146,7 +147,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
stack_desc = *stack_ptr;
- /* This is an union acpi_operand_object */
+ /* This is a union acpi_operand_object */
switch (ACPI_GET_OBJECT_TYPE(stack_desc)) {
case ACPI_TYPE_LOCAL_REFERENCE:
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/acpica/exresop.c
index 0bb82593da72..3c3802764bfb 100644
--- a/drivers/acpi/executer/exresop.c
+++ b/drivers/acpi/acpica/exresop.c
@@ -43,10 +43,11 @@
*/
#include <acpi/acpi.h>
-#include <acpi/amlcode.h>
-#include <acpi/acparser.h>
-#include <acpi/acinterp.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acparser.h"
+#include "acinterp.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exresop")
diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/acpica/exstore.c
index 3318df4cbd98..e35e9b4f6a4e 100644
--- a/drivers/acpi/executer/exstore.c
+++ b/drivers/acpi/acpica/exstore.c
@@ -43,10 +43,11 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acdispat.h>
-#include <acpi/acinterp.h>
-#include <acpi/amlcode.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "amlcode.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exstore")
@@ -274,7 +275,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
*
* PARAMETERS: *source_desc - Value to be stored
* *dest_desc - Where to store it. Must be an NS node
- * or an union acpi_operand_object of type
+ * or a union acpi_operand_object of type
* Reference;
* walk_state - Current walk state
*
diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/acpica/exstoren.c
index eef61a00803e..145d15305f70 100644
--- a/drivers/acpi/executer/exstoren.c
+++ b/drivers/acpi/acpica/exstoren.c
@@ -44,8 +44,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/amlcode.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exstoren")
diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/acpica/exstorob.c
index 9a75ff09fb0c..67340cc70142 100644
--- a/drivers/acpi/executer/exstorob.c
+++ b/drivers/acpi/acpica/exstorob.c
@@ -43,7 +43,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acinterp.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exstorob")
diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/acpica/exsystem.c
index 68990f1df371..3d00b9357233 100644
--- a/drivers/acpi/executer/exsystem.c
+++ b/drivers/acpi/acpica/exsystem.c
@@ -43,7 +43,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acinterp.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exsystem")
diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/acpica/exutils.c
index 86c03880b523..32b85d68e756 100644
--- a/drivers/acpi/executer/exutils.c
+++ b/drivers/acpi/acpica/exutils.c
@@ -59,8 +59,9 @@
#define DEFINE_AML_GLOBALS
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/amlcode.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exutils")
diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/acpica/hwacpi.c
index 816894ea839e..a9d4fea4167f 100644
--- a/drivers/acpi/hardware/hwacpi.c
+++ b/drivers/acpi/acpica/hwacpi.c
@@ -43,6 +43,7 @@
*/
#include <acpi/acpi.h>
+#include "accommon.h"
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME("hwacpi")
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index 0b80db9d9197..2013b66745d2 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -43,7 +43,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acevents.h>
+#include "accommon.h"
+#include "acevents.h"
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME("hwgpe")
@@ -51,7 +52,8 @@ ACPI_MODULE_NAME("hwgpe")
/* Local prototypes */
static acpi_status
acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
- struct acpi_gpe_block_info *gpe_block);
+ struct acpi_gpe_block_info *gpe_block,
+ void *context);
/******************************************************************************
*
@@ -80,8 +82,7 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/* Get current value of the enable register that contains this GPE */
- status = acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, &enable_mask,
- &gpe_register_info->enable_address);
+ status = acpi_read(&enable_mask, &gpe_register_info->enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -95,9 +96,7 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/* Write the updated enable mask */
- status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, enable_mask,
- &gpe_register_info->enable_address);
-
+ status = acpi_write(enable_mask, &gpe_register_info->enable_address);
return (status);
}
@@ -132,8 +131,8 @@ acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info)
/* Write the entire GPE (runtime) enable register */
- status = acpi_hw_low_level_write(8, gpe_register_info->enable_for_run,
- &gpe_register_info->enable_address);
+ status = acpi_write(gpe_register_info->enable_for_run,
+ &gpe_register_info->enable_address);
return (status);
}
@@ -166,9 +165,8 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
* Write a one to the appropriate bit in the status register to
* clear this GPE.
*/
- status = acpi_hw_low_level_write(8, register_bit,
- &gpe_event_info->register_info->
- status_address);
+ status = acpi_write(register_bit,
+ &gpe_event_info->register_info->status_address);
return (status);
}
@@ -227,9 +225,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
/* GPE currently active (status bit == 1)? */
- status =
- acpi_hw_low_level_read(8, &in_byte,
- &gpe_register_info->status_address);
+ status = acpi_read(&in_byte, &gpe_register_info->status_address);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
@@ -260,8 +256,8 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
******************************************************************************/
acpi_status
-acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
- struct acpi_gpe_block_info * gpe_block)
+acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block, void *context)
{
u32 i;
acpi_status status;
@@ -272,9 +268,9 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
/* Disable all GPEs in this register */
- status = acpi_hw_low_level_write(8, 0x00,
- &gpe_block->register_info[i].
- enable_address);
+ status =
+ acpi_write(0x00,
+ &gpe_block->register_info[i].enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -297,8 +293,8 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
******************************************************************************/
acpi_status
-acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
- struct acpi_gpe_block_info * gpe_block)
+acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block, void *context)
{
u32 i;
acpi_status status;
@@ -309,9 +305,9 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
/* Clear status on all GPEs in this register */
- status = acpi_hw_low_level_write(8, 0xFF,
- &gpe_block->register_info[i].
- status_address);
+ status =
+ acpi_write(0xFF,
+ &gpe_block->register_info[i].status_address);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -335,8 +331,8 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
******************************************************************************/
acpi_status
-acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
- struct acpi_gpe_block_info * gpe_block)
+acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block, void *context)
{
u32 i;
acpi_status status;
@@ -352,12 +348,9 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
/* Enable all "runtime" GPEs in this register */
- status =
- acpi_hw_low_level_write(8,
- gpe_block->register_info[i].
- enable_for_run,
- &gpe_block->register_info[i].
- enable_address);
+ status = acpi_write(gpe_block->register_info[i].enable_for_run,
+ &gpe_block->register_info[i].
+ enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -382,7 +375,8 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info,
static acpi_status
acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
- struct acpi_gpe_block_info *gpe_block)
+ struct acpi_gpe_block_info *gpe_block,
+ void *context)
{
u32 i;
acpi_status status;
@@ -396,11 +390,9 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/* Enable all "wake" GPEs in this register */
- status = acpi_hw_low_level_write(8,
- gpe_block->register_info[i].
- enable_for_wake,
- &gpe_block->register_info[i].
- enable_address);
+ status = acpi_write(gpe_block->register_info[i].enable_for_wake,
+ &gpe_block->register_info[i].
+ enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -427,8 +419,8 @@ acpi_status acpi_hw_disable_all_gpes(void)
ACPI_FUNCTION_TRACE(hw_disable_all_gpes);
- status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block);
- status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block);
+ status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL);
+ status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL);
return_ACPI_STATUS(status);
}
@@ -450,7 +442,7 @@ acpi_status acpi_hw_enable_all_runtime_gpes(void)
ACPI_FUNCTION_TRACE(hw_enable_all_runtime_gpes);
- status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block);
+ status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block, NULL);
return_ACPI_STATUS(status);
}
@@ -472,6 +464,6 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void)
ACPI_FUNCTION_TRACE(hw_enable_all_wakeup_gpes);
- status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block);
+ status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block, NULL);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
new file mode 100644
index 000000000000..4dc43b018517
--- /dev/null
+++ b/drivers/acpi/acpica/hwregs.c
@@ -0,0 +1,353 @@
+
+/*******************************************************************************
+ *
+ * Module Name: hwregs - Read/write access functions for the various ACPI
+ * control and status registers.
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * 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
+ * substantially 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 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 <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acevents.h"
+
+#define _COMPONENT ACPI_HARDWARE
+ACPI_MODULE_NAME("hwregs")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_hw_clear_acpi_status
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clears all fixed and general purpose status bits
+ * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
+ *
+ ******************************************************************************/
+acpi_status acpi_hw_clear_acpi_status(void)
+{
+ acpi_status status;
+ acpi_cpu_flags lock_flags = 0;
+
+ ACPI_FUNCTION_TRACE(hw_clear_acpi_status);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n",
+ ACPI_BITMASK_ALL_FIXED_STATUS,
+ (u16) acpi_gbl_FADT.xpm1a_event_block.address));
+
+ lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
+
+ status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS,
+ ACPI_BITMASK_ALL_FIXED_STATUS);
+ if (ACPI_FAILURE(status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Clear the fixed events */
+
+ if (acpi_gbl_FADT.xpm1b_event_block.address) {
+ status = acpi_write(ACPI_BITMASK_ALL_FIXED_STATUS,
+ &acpi_gbl_FADT.xpm1b_event_block);
+ if (ACPI_FAILURE(status)) {
+ goto unlock_and_exit;
+ }
+ }
+
+ /* Clear the GPE Bits in all GPE registers in all GPE blocks */
+
+ status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL);
+
+ unlock_and_exit:
+ acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_hw_get_register_bit_mask
+ *
+ * PARAMETERS: register_id - Index of ACPI Register to access
+ *
+ * RETURN: The bitmask to be used when accessing the register
+ *
+ * DESCRIPTION: Map register_id into a register bitmask.
+ *
+ ******************************************************************************/
+
+struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
+{
+ ACPI_FUNCTION_ENTRY();
+
+ if (register_id > ACPI_BITREG_MAX) {
+ ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: %X",
+ register_id));
+ return (NULL);
+ }
+
+ return (&acpi_gbl_bit_register_info[register_id]);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_register_read
+ *
+ * PARAMETERS: register_id - ACPI Register ID
+ * return_value - Where the register value is returned
+ *
+ * RETURN: Status and the value read.
+ *
+ * DESCRIPTION: Read from the specified ACPI register
+ *
+ ******************************************************************************/
+acpi_status
+acpi_hw_register_read(u32 register_id, u32 * return_value)
+{
+ u32 value1 = 0;
+ u32 value2 = 0;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(hw_register_read);
+
+ switch (register_id) {
+ case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
+
+ status = acpi_read(&value1, &acpi_gbl_FADT.xpm1a_event_block);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ /* PM1B is optional */
+
+ status = acpi_read(&value2, &acpi_gbl_FADT.xpm1b_event_block);
+ value1 |= value2;
+ break;
+
+ case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */
+
+ status = acpi_read(&value1, &acpi_gbl_xpm1a_enable);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ /* PM1B is optional */
+
+ status = acpi_read(&value2, &acpi_gbl_xpm1b_enable);
+ value1 |= value2;
+ break;
+
+ case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */
+
+ status = acpi_read(&value1, &acpi_gbl_FADT.xpm1a_control_block);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ status = acpi_read(&value2, &acpi_gbl_FADT.xpm1b_control_block);
+ value1 |= value2;
+ break;
+
+ case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
+
+ status = acpi_read(&value1, &acpi_gbl_FADT.xpm2_control_block);
+ break;
+
+ case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
+
+ status = acpi_read(&value1, &acpi_gbl_FADT.xpm_timer_block);
+ break;
+
+ case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
+
+ status =
+ acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8);
+ break;
+
+ default:
+ ACPI_ERROR((AE_INFO, "Unknown Register ID: %X", register_id));
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+
+ exit:
+
+ if (ACPI_SUCCESS(status)) {
+ *return_value = value1;
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_register_write
+ *
+ * PARAMETERS: register_id - ACPI Register ID
+ * Value - The value to write
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Write to the specified ACPI register
+ *
+ * NOTE: In accordance with the ACPI specification, this function automatically
+ * preserves the value of the following bits, meaning that these bits cannot be
+ * changed via this interface:
+ *
+ * PM1_CONTROL[0] = SCI_EN
+ * PM1_CONTROL[9]
+ * PM1_STATUS[11]
+ *
+ * ACPI References:
+ * 1) Hardware Ignored Bits: When software writes to a register with ignored
+ * bit fields, it preserves the ignored bit fields
+ * 2) SCI_EN: OSPM always preserves this bit position
+ *
+ ******************************************************************************/
+
+acpi_status acpi_hw_register_write(u32 register_id, u32 value)
+{
+ acpi_status status;
+ u32 read_value;
+
+ ACPI_FUNCTION_TRACE(hw_register_write);
+
+ switch (register_id) {
+ case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
+
+ /* Perform a read first to preserve certain bits (per ACPI spec) */
+
+ status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS,
+ &read_value);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ /* Insert the bits to be preserved */
+
+ ACPI_INSERT_BITS(value, ACPI_PM1_STATUS_PRESERVED_BITS,
+ read_value);
+
+ /* Now we can write the data */
+
+ status = acpi_write(value, &acpi_gbl_FADT.xpm1a_event_block);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ /* PM1B is optional */
+
+ status = acpi_write(value, &acpi_gbl_FADT.xpm1b_event_block);
+ break;
+
+ case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */
+
+ status = acpi_write(value, &acpi_gbl_xpm1a_enable);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ /* PM1B is optional */
+
+ status = acpi_write(value, &acpi_gbl_xpm1b_enable);
+ break;
+
+ case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */
+
+ /*
+ * Perform a read first to preserve certain bits (per ACPI spec)
+ */
+ status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
+ &read_value);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ /* Insert the bits to be preserved */
+
+ ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS,
+ read_value);
+
+ /* Now we can write the data */
+
+ status = acpi_write(value, &acpi_gbl_FADT.xpm1a_control_block);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ status = acpi_write(value, &acpi_gbl_FADT.xpm1b_control_block);
+ break;
+
+ case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */
+
+ status = acpi_write(value, &acpi_gbl_FADT.xpm1a_control_block);
+ break;
+
+ case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */
+
+ status = acpi_write(value, &acpi_gbl_FADT.xpm1b_control_block);
+ break;
+
+ case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
+
+ status = acpi_write(value, &acpi_gbl_FADT.xpm2_control_block);
+ break;
+
+ case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
+
+ status = acpi_write(value, &acpi_gbl_FADT.xpm_timer_block);
+ break;
+
+ case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
+
+ /* SMI_CMD is currently always in IO space */
+
+ status =
+ acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8);
+ break;
+
+ default:
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+
+ exit:
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index 25dccdf179b9..a2af2a4f2f26 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -43,7 +43,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "actables.h"
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME("hwsleep")
@@ -52,31 +53,19 @@ ACPI_MODULE_NAME("hwsleep")
*
* FUNCTION: acpi_set_firmware_waking_vector
*
- * PARAMETERS: physical_address - Physical address of ACPI real mode
+ * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode
* entry point.
*
* RETURN: Status
*
- * DESCRIPTION: Access function for the firmware_waking_vector field in FACS
+ * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS
*
******************************************************************************/
acpi_status
-acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
+acpi_set_firmware_waking_vector(u32 physical_address)
{
- struct acpi_table_facs *facs;
- acpi_status status;
-
ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
- /* Get the FACS */
-
- status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
- ACPI_CAST_INDIRECT_PTR(struct
- acpi_table_header,
- &facs));
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
/*
* According to the ACPI specification 2.0c and later, the 64-bit
@@ -85,10 +74,16 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
* Protected Mode. Some systems (for example HP dv5-1004nr) are known
* to fail to resume if the 64-bit vector is used.
*/
- if (facs->version >= 1)
- facs->xfirmware_waking_vector = 0;
- facs->firmware_waking_vector = (u32)physical_address;
+ /* Set the 32-bit vector */
+
+ acpi_gbl_FACS->firmware_waking_vector = physical_address;
+
+ /* Clear the 64-bit vector if it exists */
+
+ if ((acpi_gbl_FACS->length > 32) && (acpi_gbl_FACS->version >= 1)) {
+ acpi_gbl_FACS->xfirmware_waking_vector = 0;
+ }
return_ACPI_STATUS(AE_OK);
}
@@ -97,48 +92,39 @@ ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
/*******************************************************************************
*
- * FUNCTION: acpi_get_firmware_waking_vector
+ * FUNCTION: acpi_set_firmware_waking_vector64
*
- * PARAMETERS: *physical_address - Where the contents of
- * the firmware_waking_vector field of
- * the FACS will be returned.
+ * PARAMETERS: physical_address - 64-bit physical address of ACPI protected
+ * mode entry point.
*
- * RETURN: Status, vector
+ * RETURN: Status
*
- * DESCRIPTION: Access function for the firmware_waking_vector field in FACS
+ * DESCRIPTION: Sets the 64-bit X_firmware_waking_vector field of the FACS, if
+ * it exists in the table.
*
******************************************************************************/
-#ifdef ACPI_FUTURE_USAGE
acpi_status
-acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
+acpi_set_firmware_waking_vector64(u64 physical_address)
{
- struct acpi_table_facs *facs;
- acpi_status status;
+ ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64);
- ACPI_FUNCTION_TRACE(acpi_get_firmware_waking_vector);
-
- if (!physical_address) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
- /* Get the FACS */
+ /* Determine if the 64-bit vector actually exists */
- status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
- ACPI_CAST_INDIRECT_PTR(struct
- acpi_table_header,
- &facs));
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ if ((acpi_gbl_FACS->length <= 32) || (acpi_gbl_FACS->version < 1)) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
}
- /* Get the vector */
- *physical_address = (acpi_physical_address)facs->firmware_waking_vector;
+ /* Clear 32-bit vector, set the 64-bit X_ vector */
+
+ acpi_gbl_FACS->firmware_waking_vector = 0;
+ acpi_gbl_FACS->xfirmware_waking_vector = physical_address;
return_ACPI_STATUS(AE_OK);
}
-ACPI_EXPORT_SYMBOL(acpi_get_firmware_waking_vector)
-#endif
+ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64)
+
/*******************************************************************************
*
* FUNCTION: acpi_enter_sleep_state_prep
diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/acpica/hwtimer.c
index b53d575491b9..b7f522c8f023 100644
--- a/drivers/acpi/hardware/hwtimer.c
+++ b/drivers/acpi/acpica/hwtimer.c
@@ -43,6 +43,7 @@
*/
#include <acpi/acpi.h>
+#include "accommon.h"
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME("hwtimer")
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/acpica/hwxface.c
index ddf792adcf96..ae597c0ab53f 100644
--- a/drivers/acpi/hardware/hwregs.c
+++ b/drivers/acpi/acpica/hwxface.c
@@ -1,10 +1,9 @@
-/*******************************************************************************
+/******************************************************************************
*
- * Module Name: hwregs - Read/write access functions for the various ACPI
- * control and status registers.
+ * Module Name: hwxface - Public ACPICA hardware interfaces
*
- ******************************************************************************/
+ *****************************************************************************/
/*
* Copyright (C) 2000 - 2008, Intel Corp.
@@ -44,209 +43,208 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acevents.h>
+#include "accommon.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_HARDWARE
-ACPI_MODULE_NAME("hwregs")
+ACPI_MODULE_NAME("hwxface")
-/*******************************************************************************
+/******************************************************************************
*
- * FUNCTION: acpi_hw_clear_acpi_status
+ * FUNCTION: acpi_reset
*
* PARAMETERS: None
*
- * RETURN: None
+ * RETURN: Status
*
- * DESCRIPTION: Clears all fixed and general purpose status bits
- * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
+ * DESCRIPTION: Set reset register in memory or IO space. Note: Does not
+ * support reset register in PCI config space, this must be
+ * handled separately.
*
******************************************************************************/
-acpi_status acpi_hw_clear_acpi_status(void)
+acpi_status acpi_reset(void)
{
+ struct acpi_generic_address *reset_reg;
acpi_status status;
- acpi_cpu_flags lock_flags = 0;
- ACPI_FUNCTION_TRACE(hw_clear_acpi_status);
+ ACPI_FUNCTION_TRACE(acpi_reset);
- ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n",
- ACPI_BITMASK_ALL_FIXED_STATUS,
- (u16) acpi_gbl_FADT.xpm1a_event_block.address));
+ reset_reg = &acpi_gbl_FADT.reset_register;
- lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
+ /* Check if the reset register is supported */
- status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS,
- ACPI_BITMASK_ALL_FIXED_STATUS);
- if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) ||
+ !reset_reg->address) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
}
- /* Clear the fixed events */
-
- if (acpi_gbl_FADT.xpm1b_event_block.address) {
- status =
- acpi_hw_low_level_write(16, ACPI_BITMASK_ALL_FIXED_STATUS,
- &acpi_gbl_FADT.xpm1b_event_block);
- if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
- }
- }
-
- /* Clear the GPE Bits in all GPE registers in all GPE blocks */
-
- status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block);
+ /* Write the reset value to the reset register */
- unlock_and_exit:
- acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags);
+ status = acpi_write(acpi_gbl_FADT.reset_value, reset_reg);
return_ACPI_STATUS(status);
}
-/*******************************************************************************
+ACPI_EXPORT_SYMBOL(acpi_reset)
+
+/******************************************************************************
*
- * FUNCTION: acpi_get_sleep_type_data
+ * FUNCTION: acpi_read
*
- * PARAMETERS: sleep_state - Numeric sleep state
- * *sleep_type_a - Where SLP_TYPa is returned
- * *sleep_type_b - Where SLP_TYPb is returned
+ * PARAMETERS: Value - Where the value is returned
+ * Reg - GAS register structure
*
- * RETURN: Status - ACPI status
+ * RETURN: Status
*
- * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep
- * state.
+ * DESCRIPTION: Read from either memory or IO space.
*
******************************************************************************/
-
-acpi_status
-acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b)
+acpi_status acpi_read(u32 *value, struct acpi_generic_address *reg)
{
- acpi_status status = AE_OK;
- struct acpi_evaluate_info *info;
-
- ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data);
-
- /* Validate parameters */
-
- if ((sleep_state > ACPI_S_STATES_MAX) || !sleep_type_a || !sleep_type_b) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
- }
+ u32 width;
+ u64 address;
+ acpi_status status;
- /* Allocate the evaluation information block */
+ ACPI_FUNCTION_NAME(acpi_read);
- info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
- if (!info) {
- return_ACPI_STATUS(AE_NO_MEMORY);
+ /*
+ * Must have a valid pointer to a GAS structure, and
+ * a non-zero address within. However, don't return an error
+ * because the PM1A/B code must not fail if B isn't present.
+ */
+ if (!reg) {
+ return (AE_OK);
}
- info->pathname =
- ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]);
-
- /* Evaluate the namespace object containing the values for this state */
-
- status = acpi_ns_evaluate(info);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "%s while evaluating SleepState [%s]\n",
- acpi_format_exception(status),
- info->pathname));
+ /* Get a local copy of the address. Handles possible alignment issues */
- goto cleanup;
+ ACPI_MOVE_64_TO_64(&address, &reg->address);
+ if (!address) {
+ return (AE_OK);
}
- /* Must have a return object */
+ /* Supported widths are 8/16/32 */
- if (!info->return_object) {
- ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]",
- info->pathname));
- status = AE_NOT_EXIST;
+ width = reg->bit_width;
+ if ((width != 8) && (width != 16) && (width != 32)) {
+ return (AE_SUPPORT);
}
- /* It must be of type Package */
+ /* Initialize entire 32-bit return value to zero */
- else if (ACPI_GET_OBJECT_TYPE(info->return_object) != ACPI_TYPE_PACKAGE) {
- ACPI_ERROR((AE_INFO,
- "Sleep State return object is not a Package"));
- status = AE_AML_OPERAND_TYPE;
- }
+ *value = 0;
/*
- * The package must have at least two elements. NOTE (March 2005): This
- * goes against the current ACPI spec which defines this object as a
- * package with one encoded DWORD element. However, existing practice
- * by BIOS vendors seems to be to have 2 or more elements, at least
- * one per sleep type (A/B).
+ * Two address spaces supported: Memory or IO.
+ * PCI_Config is not supported here because the GAS struct is insufficient
*/
- else if (info->return_object->package.count < 2) {
- ACPI_ERROR((AE_INFO,
- "Sleep State return package does not have at least two elements"));
- status = AE_AML_NO_OPERAND;
- }
+ switch (reg->space_id) {
+ case ACPI_ADR_SPACE_SYSTEM_MEMORY:
- /* The first two elements must both be of type Integer */
+ status = acpi_os_read_memory((acpi_physical_address) address,
+ value, width);
+ break;
- else if ((ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[0])
- != ACPI_TYPE_INTEGER) ||
- (ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[1])
- != ACPI_TYPE_INTEGER)) {
- ACPI_ERROR((AE_INFO,
- "Sleep State return package elements are not both Integers (%s, %s)",
- acpi_ut_get_object_type_name(info->return_object->
- package.elements[0]),
- acpi_ut_get_object_type_name(info->return_object->
- package.elements[1])));
- status = AE_AML_OPERAND_TYPE;
- } else {
- /* Valid _Sx_ package size, type, and value */
+ case ACPI_ADR_SPACE_SYSTEM_IO:
- *sleep_type_a = (u8)
- (info->return_object->package.elements[0])->integer.value;
- *sleep_type_b = (u8)
- (info->return_object->package.elements[1])->integer.value;
- }
+ status =
+ acpi_os_read_port((acpi_io_address) address, value, width);
+ break;
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "While evaluating SleepState [%s], bad Sleep object %p type %s",
- info->pathname, info->return_object,
- acpi_ut_get_object_type_name(info->
- return_object)));
+ default:
+ ACPI_ERROR((AE_INFO,
+ "Unsupported address space: %X", reg->space_id));
+ return (AE_BAD_PARAMETER);
}
- acpi_ut_remove_reference(info->return_object);
+ ACPI_DEBUG_PRINT((ACPI_DB_IO,
+ "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
+ *value, width, ACPI_FORMAT_UINT64(address),
+ acpi_ut_get_region_name(reg->space_id)));
- cleanup:
- ACPI_FREE(info);
- return_ACPI_STATUS(status);
+ return (status);
}
-ACPI_EXPORT_SYMBOL(acpi_get_sleep_type_data)
+ACPI_EXPORT_SYMBOL(acpi_read)
-/*******************************************************************************
+/******************************************************************************
*
- * FUNCTION: acpi_hw_get_register_bit_mask
+ * FUNCTION: acpi_write
*
- * PARAMETERS: register_id - Index of ACPI Register to access
+ * PARAMETERS: Value - To be written
+ * Reg - GAS register structure
*
- * RETURN: The bitmask to be used when accessing the register
+ * RETURN: Status
*
- * DESCRIPTION: Map register_id into a register bitmask.
+ * DESCRIPTION: Write to either memory or IO space.
*
******************************************************************************/
-struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
+acpi_status acpi_write(u32 value, struct acpi_generic_address *reg)
{
- ACPI_FUNCTION_ENTRY();
+ u32 width;
+ u64 address;
+ acpi_status status;
- if (register_id > ACPI_BITREG_MAX) {
- ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: %X",
- register_id));
- return (NULL);
+ ACPI_FUNCTION_NAME(acpi_write);
+
+ /*
+ * Must have a valid pointer to a GAS structure, and
+ * a non-zero address within. However, don't return an error
+ * because the PM1A/B code must not fail if B isn't present.
+ */
+ if (!reg) {
+ return (AE_OK);
}
- return (&acpi_gbl_bit_register_info[register_id]);
+ /* Get a local copy of the address. Handles possible alignment issues */
+
+ ACPI_MOVE_64_TO_64(&address, &reg->address);
+ if (!address) {
+ return (AE_OK);
+ }
+
+ /* Supported widths are 8/16/32 */
+
+ width = reg->bit_width;
+ if ((width != 8) && (width != 16) && (width != 32)) {
+ return (AE_SUPPORT);
+ }
+
+ /*
+ * Two address spaces supported: Memory or IO.
+ * PCI_Config is not supported here because the GAS struct is insufficient
+ */
+ switch (reg->space_id) {
+ case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+
+ status = acpi_os_write_memory((acpi_physical_address) address,
+ value, width);
+ break;
+
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+
+ status = acpi_os_write_port((acpi_io_address) address, value,
+ width);
+ break;
+
+ default:
+ ACPI_ERROR((AE_INFO,
+ "Unsupported address space: %X", reg->space_id));
+ return (AE_BAD_PARAMETER);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_IO,
+ "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
+ value, width, ACPI_FORMAT_UINT64(address),
+ acpi_ut_get_region_name(reg->space_id)));
+
+ return (status);
}
+ACPI_EXPORT_SYMBOL(acpi_write)
+
/*******************************************************************************
*
- * FUNCTION: acpi_get_register
+ * FUNCTION: acpi_get_register_unlocked
*
* PARAMETERS: register_id - ID of ACPI bit_register to access
* return_value - Value that was read from the register
@@ -254,17 +252,16 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
* RETURN: Status and the value read from specified Register. Value
* returned is normalized to bit0 (is shifted all the way right)
*
- * DESCRIPTION: ACPI bit_register read function.
+ * DESCRIPTION: ACPI bit_register read function. Does not acquire the HW lock.
*
******************************************************************************/
-
-acpi_status acpi_get_register_unlocked(u32 register_id, u32 * return_value)
+acpi_status acpi_get_register_unlocked(u32 register_id, u32 *return_value)
{
u32 register_value = 0;
struct acpi_bit_register_info *bit_reg_info;
acpi_status status;
- ACPI_FUNCTION_TRACE(acpi_get_register);
+ ACPI_FUNCTION_TRACE(acpi_get_register_unlocked);
/* Get the info structure corresponding to the requested ACPI Register */
@@ -296,14 +293,31 @@ acpi_status acpi_get_register_unlocked(u32 register_id, u32 * return_value)
return_ACPI_STATUS(status);
}
-acpi_status acpi_get_register(u32 register_id, u32 * return_value)
+ACPI_EXPORT_SYMBOL(acpi_get_register_unlocked)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_register
+ *
+ * PARAMETERS: register_id - ID of ACPI bit_register to access
+ * return_value - Value that was read from the register
+ *
+ * RETURN: Status and the value read from specified Register. Value
+ * returned is normalized to bit0 (is shifted all the way right)
+ *
+ * DESCRIPTION: ACPI bit_register read function.
+ *
+ ******************************************************************************/
+acpi_status acpi_get_register(u32 register_id, u32 *return_value)
{
acpi_status status;
acpi_cpu_flags flags;
+
flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
status = acpi_get_register_unlocked(register_id, return_value);
acpi_os_release_lock(acpi_gbl_hardware_lock, flags);
- return status;
+
+ return (status);
}
ACPI_EXPORT_SYMBOL(acpi_get_register)
@@ -370,8 +384,9 @@ acpi_status acpi_set_register(u32 register_id, u32 value)
bit_reg_info->
access_bit_mask);
if (value) {
- status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS,
- (u16) value);
+ status =
+ acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS,
+ (u16) value);
register_value = 0;
}
break;
@@ -459,399 +474,120 @@ acpi_status acpi_set_register(u32 register_id, u32 value)
ACPI_EXPORT_SYMBOL(acpi_set_register)
-/******************************************************************************
+/*******************************************************************************
*
- * FUNCTION: acpi_hw_register_read
+ * FUNCTION: acpi_get_sleep_type_data
*
- * PARAMETERS: register_id - ACPI Register ID
- * return_value - Where the register value is returned
+ * PARAMETERS: sleep_state - Numeric sleep state
+ * *sleep_type_a - Where SLP_TYPa is returned
+ * *sleep_type_b - Where SLP_TYPb is returned
*
- * RETURN: Status and the value read.
+ * RETURN: Status - ACPI status
*
- * DESCRIPTION: Read from the specified ACPI register
+ * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep
+ * state.
*
******************************************************************************/
acpi_status
-acpi_hw_register_read(u32 register_id, u32 * return_value)
+acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
{
- u32 value1 = 0;
- u32 value2 = 0;
- acpi_status status;
-
- ACPI_FUNCTION_TRACE(hw_register_read);
-
- switch (register_id) {
- case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
-
- status =
- acpi_hw_low_level_read(16, &value1,
- &acpi_gbl_FADT.xpm1a_event_block);
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
-
- /* PM1B is optional */
-
- status =
- acpi_hw_low_level_read(16, &value2,
- &acpi_gbl_FADT.xpm1b_event_block);
- value1 |= value2;
- break;
-
- case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */
-
- status =
- acpi_hw_low_level_read(16, &value1, &acpi_gbl_xpm1a_enable);
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
-
- /* PM1B is optional */
-
- status =
- acpi_hw_low_level_read(16, &value2, &acpi_gbl_xpm1b_enable);
- value1 |= value2;
- break;
-
- case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */
-
- status =
- acpi_hw_low_level_read(16, &value1,
- &acpi_gbl_FADT.xpm1a_control_block);
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
-
- status =
- acpi_hw_low_level_read(16, &value2,
- &acpi_gbl_FADT.xpm1b_control_block);
- value1 |= value2;
- break;
-
- case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
-
- status =
- acpi_hw_low_level_read(8, &value1,
- &acpi_gbl_FADT.xpm2_control_block);
- break;
-
- case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
-
- status =
- acpi_hw_low_level_read(32, &value1,
- &acpi_gbl_FADT.xpm_timer_block);
- break;
+ acpi_status status = AE_OK;
+ struct acpi_evaluate_info *info;
- case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
+ ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data);
- status =
- acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8);
- break;
+ /* Validate parameters */
- default:
- ACPI_ERROR((AE_INFO, "Unknown Register ID: %X", register_id));
- status = AE_BAD_PARAMETER;
- break;
+ if ((sleep_state > ACPI_S_STATES_MAX) || !sleep_type_a || !sleep_type_b) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- exit:
+ /* Allocate the evaluation information block */
- if (ACPI_SUCCESS(status)) {
- *return_value = value1;
+ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
+ if (!info) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- return_ACPI_STATUS(status);
-}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_hw_register_write
- *
- * PARAMETERS: register_id - ACPI Register ID
- * Value - The value to write
- *
- * RETURN: Status
- *
- * DESCRIPTION: Write to the specified ACPI register
- *
- * NOTE: In accordance with the ACPI specification, this function automatically
- * preserves the value of the following bits, meaning that these bits cannot be
- * changed via this interface:
- *
- * PM1_CONTROL[0] = SCI_EN
- * PM1_CONTROL[9]
- * PM1_STATUS[11]
- *
- * ACPI References:
- * 1) Hardware Ignored Bits: When software writes to a register with ignored
- * bit fields, it preserves the ignored bit fields
- * 2) SCI_EN: OSPM always preserves this bit position
- *
- ******************************************************************************/
-
-acpi_status acpi_hw_register_write(u32 register_id, u32 value)
-{
- acpi_status status;
- u32 read_value;
-
- ACPI_FUNCTION_TRACE(hw_register_write);
-
- switch (register_id) {
- case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
-
- /* Perform a read first to preserve certain bits (per ACPI spec) */
-
- status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS,
- &read_value);
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
-
- /* Insert the bits to be preserved */
-
- ACPI_INSERT_BITS(value, ACPI_PM1_STATUS_PRESERVED_BITS,
- read_value);
-
- /* Now we can write the data */
-
- status =
- acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT.xpm1a_event_block);
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
-
- /* PM1B is optional */
-
- status =
- acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT.xpm1b_event_block);
- break;
-
- case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */
-
- status =
- acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1a_enable);
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
-
- /* PM1B is optional */
-
- status =
- acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1b_enable);
- break;
-
- case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */
-
- /*
- * Perform a read first to preserve certain bits (per ACPI spec)
- */
- status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
- &read_value);
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
-
- /* Insert the bits to be preserved */
-
- ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS,
- read_value);
-
- /* Now we can write the data */
-
- status =
- acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT.xpm1a_control_block);
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
-
- status =
- acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT.xpm1b_control_block);
- break;
-
- case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */
-
- status =
- acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT.xpm1a_control_block);
- break;
-
- case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */
-
- status =
- acpi_hw_low_level_write(16, value,
- &acpi_gbl_FADT.xpm1b_control_block);
- break;
-
- case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
-
- status =
- acpi_hw_low_level_write(8, value,
- &acpi_gbl_FADT.xpm2_control_block);
- break;
-
- case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
-
- status =
- acpi_hw_low_level_write(32, value,
- &acpi_gbl_FADT.xpm_timer_block);
- break;
-
- case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
+ info->pathname =
+ ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]);
- /* SMI_CMD is currently always in IO space */
+ /* Evaluate the namespace object containing the values for this state */
- status =
- acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8);
- break;
+ status = acpi_ns_evaluate(info);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "%s while evaluating SleepState [%s]\n",
+ acpi_format_exception(status),
+ info->pathname));
- default:
- status = AE_BAD_PARAMETER;
- break;
+ goto cleanup;
}
- exit:
- return_ACPI_STATUS(status);
-}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_hw_low_level_read
- *
- * PARAMETERS: Width - 8, 16, or 32
- * Value - Where the value is returned
- * Reg - GAS register structure
- *
- * RETURN: Status
- *
- * DESCRIPTION: Read from either memory or IO space.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
-{
- u64 address;
- acpi_status status;
-
- ACPI_FUNCTION_NAME(hw_low_level_read);
+ /* Must have a return object */
- /*
- * Must have a valid pointer to a GAS structure, and
- * a non-zero address within. However, don't return an error
- * because the PM1A/B code must not fail if B isn't present.
- */
- if (!reg) {
- return (AE_OK);
+ if (!info->return_object) {
+ ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]",
+ info->pathname));
+ status = AE_NOT_EXIST;
}
- /* Get a local copy of the address. Handles possible alignment issues */
+ /* It must be of type Package */
- ACPI_MOVE_64_TO_64(&address, &reg->address);
- if (!address) {
- return (AE_OK);
+ else if (ACPI_GET_OBJECT_TYPE(info->return_object) != ACPI_TYPE_PACKAGE) {
+ ACPI_ERROR((AE_INFO,
+ "Sleep State return object is not a Package"));
+ status = AE_AML_OPERAND_TYPE;
}
- *value = 0;
/*
- * Two address spaces supported: Memory or IO.
- * PCI_Config is not supported here because the GAS struct is insufficient
+ * The package must have at least two elements. NOTE (March 2005): This
+ * goes against the current ACPI spec which defines this object as a
+ * package with one encoded DWORD element. However, existing practice
+ * by BIOS vendors seems to be to have 2 or more elements, at least
+ * one per sleep type (A/B).
*/
- switch (reg->space_id) {
- case ACPI_ADR_SPACE_SYSTEM_MEMORY:
-
- status = acpi_os_read_memory((acpi_physical_address) address,
- value, width);
- break;
-
- case ACPI_ADR_SPACE_SYSTEM_IO:
-
- status =
- acpi_os_read_port((acpi_io_address) address, value, width);
- break;
-
- default:
+ else if (info->return_object->package.count < 2) {
ACPI_ERROR((AE_INFO,
- "Unsupported address space: %X", reg->space_id));
- return (AE_BAD_PARAMETER);
+ "Sleep State return package does not have at least two elements"));
+ status = AE_AML_NO_OPERAND;
}
- ACPI_DEBUG_PRINT((ACPI_DB_IO,
- "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
- *value, width, ACPI_FORMAT_UINT64(address),
- acpi_ut_get_region_name(reg->space_id)));
-
- return (status);
-}
-
-/******************************************************************************
- *
- * FUNCTION: acpi_hw_low_level_write
- *
- * PARAMETERS: Width - 8, 16, or 32
- * Value - To be written
- * Reg - GAS register structure
- *
- * RETURN: Status
- *
- * DESCRIPTION: Write to either memory or IO space.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
-{
- u64 address;
- acpi_status status;
-
- ACPI_FUNCTION_NAME(hw_low_level_write);
-
- /*
- * Must have a valid pointer to a GAS structure, and
- * a non-zero address within. However, don't return an error
- * because the PM1A/B code must not fail if B isn't present.
- */
- if (!reg) {
- return (AE_OK);
- }
+ /* The first two elements must both be of type Integer */
- /* Get a local copy of the address. Handles possible alignment issues */
+ else if ((ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[0])
+ != ACPI_TYPE_INTEGER) ||
+ (ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[1])
+ != ACPI_TYPE_INTEGER)) {
+ ACPI_ERROR((AE_INFO,
+ "Sleep State return package elements are not both Integers (%s, %s)",
+ acpi_ut_get_object_type_name(info->return_object->
+ package.elements[0]),
+ acpi_ut_get_object_type_name(info->return_object->
+ package.elements[1])));
+ status = AE_AML_OPERAND_TYPE;
+ } else {
+ /* Valid _Sx_ package size, type, and value */
- ACPI_MOVE_64_TO_64(&address, &reg->address);
- if (!address) {
- return (AE_OK);
+ *sleep_type_a = (u8)
+ (info->return_object->package.elements[0])->integer.value;
+ *sleep_type_b = (u8)
+ (info->return_object->package.elements[1])->integer.value;
}
- /*
- * Two address spaces supported: Memory or IO.
- * PCI_Config is not supported here because the GAS struct is insufficient
- */
- switch (reg->space_id) {
- case ACPI_ADR_SPACE_SYSTEM_MEMORY:
-
- status = acpi_os_write_memory((acpi_physical_address) address,
- value, width);
- break;
-
- case ACPI_ADR_SPACE_SYSTEM_IO:
-
- status = acpi_os_write_port((acpi_io_address) address, value,
- width);
- break;
-
- default:
- ACPI_ERROR((AE_INFO,
- "Unsupported address space: %X", reg->space_id));
- return (AE_BAD_PARAMETER);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "While evaluating SleepState [%s], bad Sleep object %p type %s",
+ info->pathname, info->return_object,
+ acpi_ut_get_object_type_name(info->
+ return_object)));
}
- ACPI_DEBUG_PRINT((ACPI_DB_IO,
- "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
- value, width, ACPI_FORMAT_UINT64(address),
- acpi_ut_get_region_name(reg->space_id)));
+ acpi_ut_remove_reference(info->return_object);
- return (status);
+ cleanup:
+ ACPI_FREE(info);
+ return_ACPI_STATUS(status);
}
+
+ACPI_EXPORT_SYMBOL(acpi_get_sleep_type_data)
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/acpica/nsaccess.c
index c39a7f68b889..88303ebe924c 100644
--- a/drivers/acpi/namespace/nsaccess.c
+++ b/drivers/acpi/acpica/nsaccess.c
@@ -42,9 +42,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/amlcode.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acdispat.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acnamesp.h"
+#include "acdispat.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsaccess")
@@ -165,12 +166,9 @@ acpi_status acpi_ns_root_initialize(void)
obj_desc->method.method_flags =
AML_METHOD_INTERNAL_ONLY;
-
-#ifndef ACPI_DUMP_APP
obj_desc->method.implementation =
acpi_ut_osi_implementation;
#endif
-#endif
break;
case ACPI_TYPE_INTEGER:
@@ -521,11 +519,11 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
}
/*
- * Search namespace for each segment of the name. Loop through and
+ * Search namespace for each segment of the name. Loop through and
* verify (or add to the namespace) each name segment.
*
* The object type is significant only at the last name
- * segment. (We don't care about the types along the path, only
+ * segment. (We don't care about the types along the path, only
* the type of the final target object.)
*/
this_search_type = ACPI_TYPE_ANY;
@@ -591,6 +589,10 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
* segments).
*/
if (this_node->type == ACPI_TYPE_LOCAL_ALIAS) {
+ if (!this_node->object) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
if (acpi_ns_opens_scope
(((struct acpi_namespace_node *)this_node->
object)->type)) {
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/acpica/nsalloc.c
index 3a1740ac2edc..f976d848fe82 100644
--- a/drivers/acpi/namespace/nsalloc.c
+++ b/drivers/acpi/acpica/nsalloc.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsalloc")
diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/acpica/nsdump.c
index cc0ae39440e4..0da33c8e9ba2 100644
--- a/drivers/acpi/namespace/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsdump")
diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c
index 428f50fde11a..41994fe7fbb8 100644
--- a/drivers/acpi/namespace/nsdumpdv.c
+++ b/drivers/acpi/acpica/nsdumpdv.c
@@ -42,6 +42,7 @@
*/
#include <acpi/acpi.h>
+#include "accommon.h"
/* TBD: This entire module is apparently obsolete and should be removed */
@@ -49,7 +50,7 @@
ACPI_MODULE_NAME("nsdumpdv")
#ifdef ACPI_OBSOLETE_FUNCTIONS
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
-#include <acpi/acnamesp.h>
+#include "acnamesp.h"
/*******************************************************************************
*
* FUNCTION: acpi_ns_dump_one_device
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/acpica/nseval.c
index 4cdf03ac2b46..0f3d5f9b5966 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -42,9 +42,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/acinterp.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "acinterp.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nseval")
@@ -89,6 +90,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
/* Initialize the return value to an invalid object */
info->return_object = NULL;
+ info->param_count = 0;
/*
* Get the actual namespace node for the target object. Handles these cases:
@@ -141,41 +143,17 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
return_ACPI_STATUS(AE_NULL_OBJECT);
}
- /*
- * Calculate the number of arguments being passed to the method
- */
+ /* Count the number of arguments being passed to the method */
- info->param_count = 0;
if (info->parameters) {
- while (info->parameters[info->param_count])
+ while (info->parameters[info->param_count]) {
+ if (info->param_count > ACPI_METHOD_MAX_ARG) {
+ return_ACPI_STATUS(AE_LIMIT);
+ }
info->param_count++;
+ }
}
- /*
- * Warning if too few or too many arguments have been passed by the
- * caller. We don't want to abort here with an error because an
- * incorrect number of arguments may not cause the method to fail.
- * However, the method will fail if there are too few arguments passed
- * and the method attempts to use one of the missing ones.
- */
-
- if (info->param_count < info->obj_desc->method.param_count) {
- ACPI_WARNING((AE_INFO,
- "Insufficient arguments - "
- "method [%4.4s] needs %d, found %d",
- acpi_ut_get_node_name(info->resolved_node),
- info->obj_desc->method.param_count,
- info->param_count));
- } else if (info->param_count >
- info->obj_desc->method.param_count) {
- ACPI_WARNING((AE_INFO,
- "Excess arguments - "
- "method [%4.4s] needs %d, found %d",
- acpi_ut_get_node_name(info->
- resolved_node),
- info->obj_desc->method.param_count,
- info->param_count));
- }
ACPI_DUMP_PATHNAME(info->resolved_node, "Execute Method:",
ACPI_LV_INFO, _COMPONENT);
@@ -264,32 +242,13 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
}
}
- /* Validation of return values for ACPI-predefined methods and objects */
-
- if ((status == AE_OK) || (status == AE_CTRL_RETURN_VALUE)) {
- /*
- * If this is the first evaluation, check the return value. This
- * ensures that any warnings will only be emitted during the very
- * first evaluation of the object.
- */
- if (!(node->flags & ANOBJ_EVALUATED)) {
- /*
- * Check for a predefined ACPI name. If found, validate the
- * returned object.
- *
- * Note: Ignore return status for now, emit warnings if there are
- * problems with the returned object. May change later to abort
- * the method on invalid return object.
- */
- (void)acpi_ns_check_predefined_names(node,
- info->
- return_object);
- }
-
- /* Mark the node as having been evaluated */
-
- node->flags |= ANOBJ_EVALUATED;
- }
+ /*
+ * Check input argument count against the ASL-defined count for a method.
+ * Also check predefined names: argument count and return value against
+ * the ACPI specification. Some incorrect return value types are repaired.
+ */
+ (void)acpi_ns_check_predefined_names(node, info->param_count,
+ status, &info->return_object);
/* Check if there is a return value that must be dealt with */
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/acpica/nsinit.c
index e4c57510d798..13501cb81863 100644
--- a/drivers/acpi/namespace/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -42,9 +42,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acdispat.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acdispat.h"
+#include "acinterp.h"
#include <linux/nmi.h>
#define _COMPONENT ACPI_NAMESPACE
diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/acpica/nsload.c
index a4a412b7c029..a0ba9e12379e 100644
--- a/drivers/acpi/namespace/nsload.c
+++ b/drivers/acpi/acpica/nsload.c
@@ -42,9 +42,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acdispat.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acdispat.h"
+#include "actables.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsload")
diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/acpica/nsnames.c
index 42a39a7c96e9..ae3dc10a7e81 100644
--- a/drivers/acpi/namespace/nsnames.c
+++ b/drivers/acpi/acpica/nsnames.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/amlcode.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "amlcode.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsnames")
diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/acpica/nsobject.c
index 15fe09e24f71..08a97a57f8f9 100644
--- a/drivers/acpi/namespace/nsobject.c
+++ b/drivers/acpi/acpica/nsobject.c
@@ -43,7 +43,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsobject")
diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/acpica/nsparse.c
index a82271a9dbb3..b9e8d0070b6f 100644
--- a/drivers/acpi/namespace/nsparse.c
+++ b/drivers/acpi/acpica/nsparse.c
@@ -42,10 +42,11 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acparser.h>
-#include <acpi/acdispat.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acparser.h"
+#include "acdispat.h"
+#include "actables.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsparse")
diff --git a/drivers/acpi/namespace/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 0f17cf0898c9..452703290d35 100644
--- a/drivers/acpi/namespace/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -43,8 +43,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acpredef.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acpredef.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nspredef")
@@ -72,7 +73,7 @@ ACPI_MODULE_NAME("nspredef")
/* Local prototypes */
static acpi_status
acpi_ns_check_package(char *pathname,
- union acpi_operand_object *return_object,
+ union acpi_operand_object **return_object_ptr,
const union acpi_predefined_info *predefined);
static acpi_status
@@ -82,13 +83,18 @@ acpi_ns_check_package_elements(char *pathname,
static acpi_status
acpi_ns_check_object_type(char *pathname,
- union acpi_operand_object *return_object,
+ union acpi_operand_object **return_object_ptr,
u32 expected_btypes, u32 package_index);
static acpi_status
acpi_ns_check_reference(char *pathname,
union acpi_operand_object *return_object);
+static acpi_status
+acpi_ns_repair_object(u32 expected_btypes,
+ u32 package_index,
+ union acpi_operand_object **return_object_ptr);
+
/*
* Names for the types that can be returned by the predefined objects.
* Used for warning messages. Must be in the same order as the ACPI_RTYPEs
@@ -108,8 +114,8 @@ static const char *acpi_rtype_names[] = {
* FUNCTION: acpi_ns_check_predefined_names
*
* PARAMETERS: Node - Namespace node for the method/object
- * return_object - Object returned from the evaluation of this
- * method/object
+ * return_object_ptr - Pointer to the object returned from the
+ * evaluation of a method or object
*
* RETURN: Status
*
@@ -119,8 +125,11 @@ static const char *acpi_rtype_names[] = {
acpi_status
acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
- union acpi_operand_object *return_object)
+ u32 user_param_count,
+ acpi_status return_status,
+ union acpi_operand_object **return_object_ptr)
{
+ union acpi_operand_object *return_object = *return_object_ptr;
acpi_status status = AE_OK;
const union acpi_predefined_info *predefined;
char *pathname;
@@ -128,12 +137,6 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
/* Match the name for this method/object against the predefined list */
predefined = acpi_ns_check_for_predefined_name(node);
- if (!predefined) {
-
- /* Name was not one of the predefined names */
-
- return (AE_OK);
- }
/* Get the full pathname to the object, for use in error messages */
@@ -143,10 +146,37 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
}
/*
- * Check that the parameter count for this method is in accordance
- * with the ACPI specification.
+ * Check that the parameter count for this method matches the ASL
+ * definition. For predefined names, ensure that both the caller and
+ * the method itself are in accordance with the ACPI specification.
*/
- acpi_ns_check_parameter_count(pathname, node, predefined);
+ acpi_ns_check_parameter_count(pathname, node, user_param_count,
+ predefined);
+
+ /* If not a predefined name, we cannot validate the return object */
+
+ if (!predefined) {
+ goto exit;
+ }
+
+ /* If the method failed, we cannot validate the return object */
+
+ if ((return_status != AE_OK) && (return_status != AE_CTRL_RETURN_VALUE)) {
+ goto exit;
+ }
+
+ /*
+ * Only validate the return value on the first successful evaluation of
+ * the method. This ensures that any warnings will only be emitted during
+ * the very first evaluation of the method/object.
+ */
+ if (node->flags & ANOBJ_EVALUATED) {
+ goto exit;
+ }
+
+ /* Mark the node as having been successfully evaluated */
+
+ node->flags |= ANOBJ_EVALUATED;
/*
* If there is no return value, check if we require a return value for
@@ -171,7 +201,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
* We have a return value, but if one wasn't expected, just exit, this is
* not a problem
*
- * For example, if "Implicit return value" is enabled, methods will
+ * For example, if the "Implicit Return" feature is enabled, methods will
* always return a value
*/
if (!predefined->info.expected_btypes) {
@@ -182,7 +212,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
* Check that the type of the return object is what is expected for
* this predefined name
*/
- status = acpi_ns_check_object_type(pathname, return_object,
+ status = acpi_ns_check_object_type(pathname, return_object_ptr,
predefined->info.expected_btypes,
ACPI_NOT_PACKAGE);
if (ACPI_FAILURE(status)) {
@@ -193,11 +223,12 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
if (ACPI_GET_OBJECT_TYPE(return_object) == ACPI_TYPE_PACKAGE) {
status =
- acpi_ns_check_package(pathname, return_object, predefined);
+ acpi_ns_check_package(pathname, return_object_ptr,
+ predefined);
}
exit:
- if (pathname) {
+ if (pathname != predefined->info.name) {
ACPI_FREE(pathname);
}
@@ -210,6 +241,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
*
* PARAMETERS: Pathname - Full pathname to the node (for error msgs)
* Node - Namespace node for the method/object
+ * user_param_count - Number of args passed in by the caller
* Predefined - Pointer to entry in predefined name table
*
* RETURN: None
@@ -223,32 +255,76 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
void
acpi_ns_check_parameter_count(char *pathname,
struct acpi_namespace_node *node,
+ u32 user_param_count,
const union acpi_predefined_info *predefined)
{
u32 param_count;
u32 required_params_current;
u32 required_params_old;
- /*
- * Check that the ASL-defined parameter count is what is expected for
- * this predefined name.
- *
- * Methods have 0-7 parameters. All other types have zero.
- */
+ /* Methods have 0-7 parameters. All other types have zero. */
+
param_count = 0;
if (node->type == ACPI_TYPE_METHOD) {
param_count = node->object->method.param_count;
}
- /* Validate parameter count - allow two different legal counts (_SCP) */
+ /* Argument count check for non-predefined methods/objects */
+
+ if (!predefined) {
+ /*
+ * Warning if too few or too many arguments have been passed by the
+ * caller. An incorrect number of arguments may not cause the method
+ * to fail. However, the method will fail if there are too few
+ * arguments and the method attempts to use one of the missing ones.
+ */
+ if (user_param_count < param_count) {
+ ACPI_WARNING((AE_INFO,
+ "%s: Insufficient arguments - needs %d, found %d",
+ pathname, param_count, user_param_count));
+ } else if (user_param_count > param_count) {
+ ACPI_WARNING((AE_INFO,
+ "%s: Excess arguments - needs %d, found %d",
+ pathname, param_count, user_param_count));
+ }
+ return;
+ }
+
+ /* Allow two different legal argument counts (_SCP, etc.) */
required_params_current = predefined->info.param_count & 0x0F;
required_params_old = predefined->info.param_count >> 4;
+ if (user_param_count != ACPI_UINT32_MAX) {
+
+ /* Validate the user-supplied parameter count */
+
+ if ((user_param_count != required_params_current) &&
+ (user_param_count != required_params_old)) {
+ ACPI_WARNING((AE_INFO,
+ "%s: Parameter count mismatch - caller passed %d, ACPI requires %d",
+ pathname, user_param_count,
+ required_params_current));
+ }
+ }
+
+ /*
+ * Only validate the argument count on the first successful evaluation of
+ * the method. This ensures that any warnings will only be emitted during
+ * the very first evaluation of the method/object.
+ */
+ if (node->flags & ANOBJ_EVALUATED) {
+ return;
+ }
+
+ /*
+ * Check that the ASL-defined parameter count is what is expected for
+ * this predefined name.
+ */
if ((param_count != required_params_current) &&
(param_count != required_params_old)) {
ACPI_WARNING((AE_INFO,
- "%s: Parameter count mismatch - ASL declared %d, expected %d",
+ "%s: Parameter count mismatch - ASL declared %d, ACPI requires %d",
pathname, param_count, required_params_current));
}
}
@@ -307,8 +383,8 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
* FUNCTION: acpi_ns_check_package
*
* PARAMETERS: Pathname - Full pathname to the node (for error msgs)
- * return_object - Object returned from the evaluation of a
- * method or object
+ * return_object_ptr - Pointer to the object returned from the
+ * evaluation of a method or object
* Predefined - Pointer to entry in predefined name table
*
* RETURN: Status
@@ -320,9 +396,10 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct
static acpi_status
acpi_ns_check_package(char *pathname,
- union acpi_operand_object *return_object,
+ union acpi_operand_object **return_object_ptr,
const union acpi_predefined_info *predefined)
{
+ union acpi_operand_object *return_object = *return_object_ptr;
const union acpi_predefined_info *package;
union acpi_operand_object *sub_package;
union acpi_operand_object **elements;
@@ -408,7 +485,7 @@ acpi_ns_check_package(char *pathname,
* elements must be of the same type
*/
for (i = 0; i < count; i++) {
- status = acpi_ns_check_object_type(pathname, *elements,
+ status = acpi_ns_check_object_type(pathname, elements,
package->ret_info.
object_type1, i);
if (ACPI_FAILURE(status)) {
@@ -441,7 +518,7 @@ acpi_ns_check_package(char *pathname,
status =
acpi_ns_check_object_type(pathname,
- *elements,
+ elements,
package->
ret_info3.
object_type[i],
@@ -454,7 +531,7 @@ acpi_ns_check_package(char *pathname,
status =
acpi_ns_check_object_type(pathname,
- *elements,
+ elements,
package->
ret_info3.
tail_object_type,
@@ -471,7 +548,7 @@ acpi_ns_check_package(char *pathname,
/* First element is the (Integer) count of sub-packages to follow */
- status = acpi_ns_check_object_type(pathname, *elements,
+ status = acpi_ns_check_object_type(pathname, elements,
ACPI_RTYPE_INTEGER, 0);
if (ACPI_FAILURE(status)) {
return (status);
@@ -509,7 +586,7 @@ acpi_ns_check_package(char *pathname,
/* Each sub-object must be of type Package */
status =
- acpi_ns_check_object_type(pathname, sub_package,
+ acpi_ns_check_object_type(pathname, &sub_package,
ACPI_RTYPE_PACKAGE, i);
if (ACPI_FAILURE(status)) {
return (status);
@@ -567,12 +644,8 @@ acpi_ns_check_package(char *pathname,
for (j = 0; j < expected_count; j++) {
status =
acpi_ns_check_object_type(pathname,
- sub_elements
- [j],
- package->
- ret_info2.
- object_type
- [j], j);
+ &sub_elements[j],
+ package->ret_info2.object_type[j], j);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -611,7 +684,7 @@ acpi_ns_check_package(char *pathname,
status =
acpi_ns_check_object_type(pathname,
- *sub_elements,
+ sub_elements,
ACPI_RTYPE_INTEGER,
0);
if (ACPI_FAILURE(status)) {
@@ -708,7 +781,7 @@ acpi_ns_check_package_elements(char *pathname,
* The second group can have a count of zero.
*/
for (i = 0; i < count1; i++) {
- status = acpi_ns_check_object_type(pathname, *this_element,
+ status = acpi_ns_check_object_type(pathname, this_element,
type1, i);
if (ACPI_FAILURE(status)) {
return (status);
@@ -717,7 +790,7 @@ acpi_ns_check_package_elements(char *pathname,
}
for (i = 0; i < count2; i++) {
- status = acpi_ns_check_object_type(pathname, *this_element,
+ status = acpi_ns_check_object_type(pathname, this_element,
type2, (i + count1));
if (ACPI_FAILURE(status)) {
return (status);
@@ -733,8 +806,8 @@ acpi_ns_check_package_elements(char *pathname,
* FUNCTION: acpi_ns_check_object_type
*
* PARAMETERS: Pathname - Full pathname to the node (for error msgs)
- * return_object - Object return from the execution of this
- * method/object
+ * return_object_ptr - Pointer to the object returned from the
+ * evaluation of a method or object
* expected_btypes - Bitmap of expected return type(s)
* package_index - Index of object within parent package (if
* applicable - ACPI_NOT_PACKAGE otherwise)
@@ -748,9 +821,10 @@ acpi_ns_check_package_elements(char *pathname,
static acpi_status
acpi_ns_check_object_type(char *pathname,
- union acpi_operand_object *return_object,
+ union acpi_operand_object **return_object_ptr,
u32 expected_btypes, u32 package_index)
{
+ union acpi_operand_object *return_object = *return_object_ptr;
acpi_status status = AE_OK;
u32 return_btype;
char type_buffer[48]; /* Room for 5 types */
@@ -814,6 +888,14 @@ acpi_ns_check_object_type(char *pathname,
/* Is the object one of the expected types? */
if (!(return_btype & expected_btypes)) {
+
+ /* Type mismatch -- attempt repair of the returned object */
+
+ status = acpi_ns_repair_object(expected_btypes, package_index,
+ return_object_ptr);
+ if (ACPI_SUCCESS(status)) {
+ return (status);
+ }
goto type_error_exit;
}
@@ -898,3 +980,86 @@ acpi_ns_check_reference(char *pathname,
return (AE_AML_OPERAND_TYPE);
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_repair_object
+ *
+ * PARAMETERS: Pathname - Full pathname to the node (for error msgs)
+ * package_index - Used to determine if target is in a package
+ * return_object_ptr - Pointer to the object returned from the
+ * evaluation of a method or object
+ *
+ * RETURN: Status. AE_OK if repair was successful.
+ *
+ * DESCRIPTION: Attempt to repair/convert a return object of a type that was
+ * not expected.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ns_repair_object(u32 expected_btypes,
+ u32 package_index,
+ union acpi_operand_object **return_object_ptr)
+{
+ union acpi_operand_object *return_object = *return_object_ptr;
+ union acpi_operand_object *new_object;
+ acpi_size length;
+
+ switch (ACPI_GET_OBJECT_TYPE(return_object)) {
+ case ACPI_TYPE_BUFFER:
+
+ if (!(expected_btypes & ACPI_RTYPE_STRING)) {
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ /*
+ * Have a Buffer, expected a String, convert. Use a to_string
+ * conversion, no transform performed on the buffer data. The best
+ * example of this is the _BIF method, where the string data from
+ * the battery is often (incorrectly) returned as buffer object(s).
+ */
+ length = 0;
+ while ((length < return_object->buffer.length) &&
+ (return_object->buffer.pointer[length])) {
+ length++;
+ }
+
+ /* Allocate a new string object */
+
+ new_object = acpi_ut_create_string_object(length);
+ if (!new_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * Copy the raw buffer data with no transform. String is already NULL
+ * terminated at Length+1.
+ */
+ ACPI_MEMCPY(new_object->string.pointer,
+ return_object->buffer.pointer, length);
+
+ /* Install the new return object */
+
+ acpi_ut_remove_reference(return_object);
+ *return_object_ptr = new_object;
+
+ /*
+ * If the object is a package element, we need to:
+ * 1. Decrement the reference count of the orignal object, it was
+ * incremented when building the package
+ * 2. Increment the reference count of the new object, it will be
+ * decremented when releasing the package
+ */
+ if (package_index != ACPI_NOT_PACKAGE) {
+ acpi_ut_remove_reference(return_object);
+ acpi_ut_add_reference(new_object);
+ }
+ return (AE_OK);
+
+ default:
+ break;
+ }
+
+ return (AE_AML_OPERAND_TYPE);
+}
diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/acpica/nssearch.c
index a9a80bf811b3..6fea13f3f52d 100644
--- a/drivers/acpi/namespace/nssearch.c
+++ b/drivers/acpi/acpica/nssearch.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nssearch")
diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/acpica/nsutils.c
index b0817e1127b1..3e1149bf4aa5 100644
--- a/drivers/acpi/namespace/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -43,9 +43,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/amlcode.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "amlcode.h"
+#include "actables.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsutils")
@@ -314,9 +315,15 @@ void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info)
*
* strlen() + 1 covers the first name_seg, which has no path separator
*/
- if (acpi_ns_valid_root_prefix(next_external_char[0])) {
+ if (acpi_ns_valid_root_prefix(*next_external_char)) {
info->fully_qualified = TRUE;
next_external_char++;
+
+ /* Skip redundant root_prefix, like \\_SB.PCI0.SBRG.EC0 */
+
+ while (acpi_ns_valid_root_prefix(*next_external_char)) {
+ next_external_char++;
+ }
} else {
/*
* Handle Carat prefixes
diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/acpica/nswalk.c
index 3c905ce26d7d..200895fa2728 100644
--- a/drivers/acpi/namespace/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nswalk")
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index a085cc39c055..22a7171ac1ed 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -43,8 +43,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acinterp.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsxfeval")
diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/acpica/nsxfname.c
index 5efa4e7ddb0b..9589fea24997 100644
--- a/drivers/acpi/namespace/nsxfname.c
+++ b/drivers/acpi/acpica/nsxfname.c
@@ -43,7 +43,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsxfname")
diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c
index 2b375ee80cef..1c7efc15225f 100644
--- a/drivers/acpi/namespace/nsxfobj.c
+++ b/drivers/acpi/acpica/nsxfobj.c
@@ -43,7 +43,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsxfobj")
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/acpica/psargs.c
index d830b29b85b1..b161f3544b51 100644
--- a/drivers/acpi/parser/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -42,10 +42,11 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/amlcode.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acdispat.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acnamesp.h"
+#include "acdispat.h"
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psargs")
diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/acpica/psloop.c
index 4647039a0d8a..c5f6ce19a401 100644
--- a/drivers/acpi/parser/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -50,9 +50,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/acdispat.h>
-#include <acpi/amlcode.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "acdispat.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psloop")
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/acpica/psopcode.c
index f425ab30eae8..3bc3a60194d6 100644
--- a/drivers/acpi/parser/psopcode.c
+++ b/drivers/acpi/acpica/psopcode.c
@@ -42,9 +42,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/acopcode.h>
-#include <acpi/amlcode.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "acopcode.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psopcode")
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/acpica/psparse.c
index 68e932f215ea..70838e9b608c 100644
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/acpica/psparse.c
@@ -51,11 +51,12 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/acdispat.h>
-#include <acpi/amlcode.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "acdispat.h"
+#include "amlcode.h"
+#include "acnamesp.h"
+#include "acinterp.h"
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psparse")
@@ -447,10 +448,22 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
walk_state, walk_state->parser_state.aml,
walk_state->parser_state.aml_size));
+ if (!walk_state->parser_state.aml) {
+ return_ACPI_STATUS(AE_NULL_OBJECT);
+ }
+
/* Create and initialize a new thread state */
thread = acpi_ut_create_thread_state();
if (!thread) {
+ if (walk_state->method_desc) {
+
+ /* Executing a control method - additional cleanup */
+
+ acpi_ds_terminate_control_method(
+ walk_state->method_desc, walk_state);
+ }
+
acpi_ds_delete_walk_state(walk_state);
return_ACPI_STATUS(AE_NO_MEMORY);
}
diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/acpica/psscope.c
index ee50e67c9443..2feca5ca9581 100644
--- a/drivers/acpi/parser/psscope.c
+++ b/drivers/acpi/acpica/psscope.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
+#include "accommon.h"
+#include "acparser.h"
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psscope")
diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/acpica/pstree.c
index 1dd355ddd182..4d3389118ec3 100644
--- a/drivers/acpi/parser/pstree.c
+++ b/drivers/acpi/acpica/pstree.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/amlcode.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("pstree")
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/acpica/psutils.c
index 7cf1f65cd5bb..e636e078ad3d 100644
--- a/drivers/acpi/parser/psutils.c
+++ b/drivers/acpi/acpica/psutils.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/amlcode.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psutils")
diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/acpica/pswalk.c
index 8b86ad5a3201..78b8b791f2ae 100644
--- a/drivers/acpi/parser/pswalk.c
+++ b/drivers/acpi/acpica/pswalk.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
+#include "accommon.h"
+#include "acparser.h"
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("pswalk")
diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/acpica/psxface.c
index 270469aae842..ff06032c0f06 100644
--- a/drivers/acpi/parser/psxface.c
+++ b/drivers/acpi/acpica/psxface.c
@@ -42,9 +42,11 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
-#include <acpi/acdispat.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acparser.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "amlcode.h"
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psxface")
@@ -278,6 +280,38 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
goto cleanup;
}
+ /* Invoke an internal method if necessary */
+
+ if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
+ status = info->obj_desc->method.implementation(walk_state);
+ info->return_object = walk_state->return_desc;
+
+ /* Cleanup states */
+
+ acpi_ds_scope_stack_clear(walk_state);
+ acpi_ps_cleanup_scope(&walk_state->parser_state);
+ acpi_ds_terminate_control_method(walk_state->method_desc,
+ walk_state);
+ acpi_ds_delete_walk_state(walk_state);
+ goto cleanup;
+ }
+
+ /*
+ * Start method evaluation with an implicit return of zero.
+ * This is done for Windows compatibility.
+ */
+ if (acpi_gbl_enable_interpreter_slack) {
+ walk_state->implicit_return_obj =
+ acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
+ if (!walk_state->implicit_return_obj) {
+ status = AE_NO_MEMORY;
+ acpi_ds_delete_walk_state(walk_state);
+ goto cleanup;
+ }
+
+ walk_state->implicit_return_obj->integer.value = 0;
+ }
+
/* Parse the AML */
status = acpi_ps_parse_aml(walk_state);
diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/acpica/rsaddr.c
index 7f96332822bf..1e437bfd8db5 100644
--- a/drivers/acpi/resources/rsaddr.c
+++ b/drivers/acpi/acpica/rsaddr.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acresrc.h>
+#include "accommon.h"
+#include "acresrc.h"
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsaddr")
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/acpica/rscalc.c
index 8eaaecf92009..52865ee6bc77 100644
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/acpica/rscalc.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acresrc.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acresrc.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rscalc")
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/acpica/rscreate.c
index c0bbfa2c4193..61566b1a0616 100644
--- a/drivers/acpi/resources/rscreate.c
+++ b/drivers/acpi/acpica/rscreate.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acresrc.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acresrc.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rscreate")
@@ -124,7 +125,7 @@ acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer,
*
* FUNCTION: acpi_rs_create_pci_routing_table
*
- * PARAMETERS: package_object - Pointer to an union acpi_operand_object
+ * PARAMETERS: package_object - Pointer to a union acpi_operand_object
* package
* output_buffer - Pointer to the user's buffer
*
diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/acpica/rsdump.c
index 6bbbb7b8941a..3f0ca5a12d34 100644
--- a/drivers/acpi/resources/rsdump.c
+++ b/drivers/acpi/acpica/rsdump.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acresrc.h>
+#include "accommon.h"
+#include "acresrc.h"
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsdump")
diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/acpica/rsinfo.c
index 3f0a1fedbe0e..77b25fdb459c 100644
--- a/drivers/acpi/resources/rsinfo.c
+++ b/drivers/acpi/acpica/rsinfo.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acresrc.h>
+#include "accommon.h"
+#include "acresrc.h"
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsinfo")
diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/acpica/rsio.c
index b66d42e7402e..35a49aa95609 100644
--- a/drivers/acpi/resources/rsio.c
+++ b/drivers/acpi/acpica/rsio.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acresrc.h>
+#include "accommon.h"
+#include "acresrc.h"
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsio")
diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/acpica/rsirq.c
index a8805efc0366..2e0256983aa6 100644
--- a/drivers/acpi/resources/rsirq.c
+++ b/drivers/acpi/acpica/rsirq.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acresrc.h>
+#include "accommon.h"
+#include "acresrc.h"
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsirq")
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/acpica/rslist.c
index b78c7e797a19..1b1dbc69f087 100644
--- a/drivers/acpi/resources/rslist.c
+++ b/drivers/acpi/acpica/rslist.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acresrc.h>
+#include "accommon.h"
+#include "acresrc.h"
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rslist")
diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/acpica/rsmemory.c
index 63b21abd90bb..ddc76cebdc92 100644
--- a/drivers/acpi/resources/rsmemory.c
+++ b/drivers/acpi/acpica/rsmemory.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acresrc.h>
+#include "accommon.h"
+#include "acresrc.h"
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsmemory")
diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/acpica/rsmisc.c
index 96a6c0353255..5bc49a553284 100644
--- a/drivers/acpi/resources/rsmisc.c
+++ b/drivers/acpi/acpica/rsmisc.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acresrc.h>
+#include "accommon.h"
+#include "acresrc.h"
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsmisc")
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/acpica/rsutils.c
index f7b3bcd59ba7..bc03d5966829 100644
--- a/drivers/acpi/resources/rsutils.c
+++ b/drivers/acpi/acpica/rsutils.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acresrc.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acresrc.h"
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsutils")
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/acpica/rsxface.c
index f59f4c4e034c..69a2aa5b5d83 100644
--- a/drivers/acpi/resources/rsxface.c
+++ b/drivers/acpi/acpica/rsxface.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acresrc.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acresrc.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsxface")
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 2817158fb6a1..3636e4f8fb73 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -42,15 +42,16 @@
*/
#include <acpi/acpi.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "actables.h"
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbfadt")
/* Local prototypes */
-static void inline
+static inline void
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
- u8 byte_width, u64 address);
+ u8 space_id, u8 byte_width, u64 address);
static void acpi_tb_convert_fadt(void);
@@ -60,9 +61,10 @@ static void acpi_tb_validate_fadt(void);
typedef struct acpi_fadt_info {
char *name;
- u8 target;
- u8 source;
+ u8 address64;
+ u8 address32;
u8 length;
+ u8 default_length;
u8 type;
} acpi_fadt_info;
@@ -71,37 +73,61 @@ typedef struct acpi_fadt_info {
#define ACPI_FADT_SEPARATE_LENGTH 2
static struct acpi_fadt_info fadt_info_table[] = {
- {"Pm1aEventBlock", ACPI_FADT_OFFSET(xpm1a_event_block),
+ {"Pm1aEventBlock",
+ ACPI_FADT_OFFSET(xpm1a_event_block),
ACPI_FADT_OFFSET(pm1a_event_block),
- ACPI_FADT_OFFSET(pm1_event_length), ACPI_FADT_REQUIRED},
+ ACPI_FADT_OFFSET(pm1_event_length),
+ ACPI_PM1_REGISTER_WIDTH * 2, /* Enable + Status register */
+ ACPI_FADT_REQUIRED},
- {"Pm1bEventBlock", ACPI_FADT_OFFSET(xpm1b_event_block),
+ {"Pm1bEventBlock",
+ ACPI_FADT_OFFSET(xpm1b_event_block),
ACPI_FADT_OFFSET(pm1b_event_block),
- ACPI_FADT_OFFSET(pm1_event_length), 0},
+ ACPI_FADT_OFFSET(pm1_event_length),
+ ACPI_PM1_REGISTER_WIDTH * 2, /* Enable + Status register */
+ 0},
- {"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block),
+ {"Pm1aControlBlock",
+ ACPI_FADT_OFFSET(xpm1a_control_block),
ACPI_FADT_OFFSET(pm1a_control_block),
- ACPI_FADT_OFFSET(pm1_control_length), ACPI_FADT_REQUIRED},
+ ACPI_FADT_OFFSET(pm1_control_length),
+ ACPI_PM1_REGISTER_WIDTH,
+ ACPI_FADT_REQUIRED},
- {"Pm1bControlBlock", ACPI_FADT_OFFSET(xpm1b_control_block),
+ {"Pm1bControlBlock",
+ ACPI_FADT_OFFSET(xpm1b_control_block),
ACPI_FADT_OFFSET(pm1b_control_block),
- ACPI_FADT_OFFSET(pm1_control_length), 0},
+ ACPI_FADT_OFFSET(pm1_control_length),
+ ACPI_PM1_REGISTER_WIDTH,
+ 0},
- {"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block),
+ {"Pm2ControlBlock",
+ ACPI_FADT_OFFSET(xpm2_control_block),
ACPI_FADT_OFFSET(pm2_control_block),
- ACPI_FADT_OFFSET(pm2_control_length), ACPI_FADT_SEPARATE_LENGTH},
+ ACPI_FADT_OFFSET(pm2_control_length),
+ ACPI_PM2_REGISTER_WIDTH,
+ ACPI_FADT_SEPARATE_LENGTH},
- {"PmTimerBlock", ACPI_FADT_OFFSET(xpm_timer_block),
+ {"PmTimerBlock",
+ ACPI_FADT_OFFSET(xpm_timer_block),
ACPI_FADT_OFFSET(pm_timer_block),
- ACPI_FADT_OFFSET(pm_timer_length), ACPI_FADT_REQUIRED},
+ ACPI_FADT_OFFSET(pm_timer_length),
+ ACPI_PM_TIMER_WIDTH,
+ ACPI_FADT_REQUIRED},
- {"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block),
+ {"Gpe0Block",
+ ACPI_FADT_OFFSET(xgpe0_block),
ACPI_FADT_OFFSET(gpe0_block),
- ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_SEPARATE_LENGTH},
+ ACPI_FADT_OFFSET(gpe0_block_length),
+ 0,
+ ACPI_FADT_SEPARATE_LENGTH},
- {"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block),
+ {"Gpe1Block",
+ ACPI_FADT_OFFSET(xgpe1_block),
ACPI_FADT_OFFSET(gpe1_block),
- ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_SEPARATE_LENGTH}
+ ACPI_FADT_OFFSET(gpe1_block_length),
+ 0,
+ ACPI_FADT_SEPARATE_LENGTH}
};
#define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info))
@@ -122,9 +148,9 @@ static struct acpi_fadt_info fadt_info_table[] = {
*
******************************************************************************/
-static void inline
+static inline void
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
- u8 byte_width, u64 address)
+ u8 space_id, u8 byte_width, u64 address)
{
/*
@@ -135,10 +161,10 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
/* All other fields are byte-wide */
- generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO;
- generic_address->bit_width = byte_width << 3;
+ generic_address->space_id = space_id;
+ generic_address->bit_width = (u8)ACPI_MUL_8(byte_width);
generic_address->bit_offset = 0;
- generic_address->access_width = 0;
+ generic_address->access_width = 0; /* Access width ANY */
}
/*******************************************************************************
@@ -225,7 +251,8 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
*/
if (length > sizeof(struct acpi_table_fadt)) {
ACPI_WARNING((AE_INFO,
- "FADT (revision %u) is longer than ACPI 2.0 version, truncating length 0x%X to 0x%zX",
+ "FADT (revision %u) is longer than ACPI 2.0 version, "
+ "truncating length 0x%X to 0x%zX",
table->revision, (unsigned)length,
sizeof(struct acpi_table_fadt)));
}
@@ -244,7 +271,6 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
* 2) Validate some of the important values within the FADT
*/
acpi_tb_convert_fadt();
- acpi_tb_validate_fadt();
}
/*******************************************************************************
@@ -278,22 +304,36 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
static void acpi_tb_convert_fadt(void)
{
- u8 pm1_register_length;
- struct acpi_generic_address *target;
+ u8 pm1_register_bit_width;
+ u8 pm1_register_byte_width;
+ struct acpi_generic_address *target64;
u32 i;
/* Update the local FADT table header length */
acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
- /* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary */
-
+ /*
+ * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary.
+ * Later code will always use the X 64-bit field. Also, check for an
+ * address mismatch between the 32-bit and 64-bit address fields
+ * (FIRMWARE_CTRL/X_FIRMWARE_CTRL, DSDT/X_DSDT) which would indicate
+ * the presence of two FACS or two DSDT tables.
+ */
if (!acpi_gbl_FADT.Xfacs) {
acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs;
+ } else if (acpi_gbl_FADT.facs &&
+ (acpi_gbl_FADT.Xfacs != (u64) acpi_gbl_FADT.facs)) {
+ ACPI_WARNING((AE_INFO,
+ "32/64 FACS address mismatch in FADT - two FACS tables!"));
}
if (!acpi_gbl_FADT.Xdsdt) {
acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt;
+ } else if (acpi_gbl_FADT.dsdt &&
+ (acpi_gbl_FADT.Xdsdt != (u64) acpi_gbl_FADT.dsdt)) {
+ ACPI_WARNING((AE_INFO,
+ "32/64 DSDT address mismatch in FADT - two DSDT tables!"));
}
/*
@@ -312,18 +352,23 @@ static void acpi_tb_convert_fadt(void)
}
/*
- * Expand the ACPI 1.0 32-bit V1.0 addresses to the ACPI 2.0 64-bit "X"
- * generic address structures as necessary.
+ * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X"
+ * generic address structures as necessary. Later code will always use
+ * the 64-bit address structures.
*/
for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
- target =
+ target64 =
ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
- fadt_info_table[i].target);
+ fadt_info_table[i].address64);
- /* Expand only if the X target is null */
+ /* Expand only if the 64-bit X target is null */
- if (!target->address) {
- acpi_tb_init_generic_address(target,
+ if (!target64->address) {
+
+ /* The space_id is always I/O for the 32-bit legacy address fields */
+
+ acpi_tb_init_generic_address(target64,
+ ACPI_ADR_SPACE_SYSTEM_IO,
*ACPI_ADD_PTR(u8,
&acpi_gbl_FADT,
fadt_info_table
@@ -332,11 +377,64 @@ static void acpi_tb_convert_fadt(void)
&acpi_gbl_FADT,
fadt_info_table
[i].
- source));
+ address32));
+ }
+ }
+
+ /* Validate FADT values now, before we make any changes */
+
+ acpi_tb_validate_fadt();
+
+ /*
+ * Optionally check all register lengths against the default values and
+ * update them if they are incorrect.
+ */
+ if (acpi_gbl_use_default_register_widths) {
+ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+ target64 =
+ ACPI_ADD_PTR(struct acpi_generic_address,
+ &acpi_gbl_FADT,
+ fadt_info_table[i].address64);
+
+ /*
+ * If a valid register (Address != 0) and the (default_length > 0)
+ * (Not a GPE register), then check the width against the default.
+ */
+ if ((target64->address) &&
+ (fadt_info_table[i].default_length > 0) &&
+ (fadt_info_table[i].default_length !=
+ target64->bit_width)) {
+ ACPI_WARNING((AE_INFO,
+ "Invalid length for %s: %d, using default %d",
+ fadt_info_table[i].name,
+ target64->bit_width,
+ fadt_info_table[i].
+ default_length));
+
+ /* Incorrect size, set width to the default */
+
+ target64->bit_width =
+ fadt_info_table[i].default_length;
+ }
}
}
/*
+ * Get the length of the individual PM1 registers (enable and status).
+ * Each register is defined to be (event block length / 2).
+ */
+ pm1_register_bit_width =
+ (u8)ACPI_DIV_2(acpi_gbl_FADT.xpm1a_event_block.bit_width);
+ pm1_register_byte_width = (u8)ACPI_DIV_8(pm1_register_bit_width);
+
+ /*
+ * Adjust the lengths of the PM1 Event Blocks so that they can be used to
+ * access the PM1 status register(s). Use (width / 2)
+ */
+ acpi_gbl_FADT.xpm1a_event_block.bit_width = pm1_register_bit_width;
+ acpi_gbl_FADT.xpm1b_event_block.bit_width = pm1_register_bit_width;
+
+ /*
* Calculate separate GAS structs for the PM1 Enable registers.
* These addresses do not appear (directly) in the FADT, so it is
* useful to calculate them once, here.
@@ -356,14 +454,14 @@ static void acpi_tb_convert_fadt(void)
" PM1_EVT_LEN (%u)\n",
acpi_gbl_FADT.xpm1a_event_block.bit_width,
acpi_gbl_FADT.pm1_event_length);
- pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length);
/* The PM1A register block is required */
acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
- pm1_register_length,
+ acpi_gbl_FADT.xpm1a_event_block.space_id,
+ pm1_register_byte_width,
(acpi_gbl_FADT.xpm1a_event_block.address +
- pm1_register_length));
+ pm1_register_byte_width));
/* Don't forget to copy space_id of the GAS */
acpi_gbl_xpm1a_enable.space_id =
acpi_gbl_FADT.xpm1a_event_block.space_id;
@@ -379,9 +477,10 @@ static void acpi_tb_convert_fadt(void)
acpi_gbl_FADT.xpm1b_event_block.bit_width,
acpi_gbl_FADT.pm1_event_length);
acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
- pm1_register_length,
+ acpi_gbl_FADT.xpm1b_event_block.space_id,
+ pm1_register_byte_width,
(acpi_gbl_FADT.xpm1b_event_block.
- address + pm1_register_length));
+ address + pm1_register_byte_width));
/* Don't forget to copy space_id of the GAS */
acpi_gbl_xpm1b_enable.space_id =
acpi_gbl_FADT.xpm1b_event_block.space_id;
@@ -411,26 +510,63 @@ static void acpi_tb_convert_fadt(void)
static void acpi_tb_validate_fadt(void)
{
+ char *name;
u32 *address32;
struct acpi_generic_address *address64;
u8 length;
u32 i;
- /* Examine all of the 64-bit extended address fields (X fields) */
+ /*
+ * Check for FACS and DSDT address mismatches. An address mismatch between
+ * the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and
+ * DSDT/X_DSDT) would indicate the presence of two FACS or two DSDT tables.
+ */
+ if (acpi_gbl_FADT.facs &&
+ (acpi_gbl_FADT.Xfacs != (u64) acpi_gbl_FADT.facs)) {
+ ACPI_WARNING((AE_INFO,
+ "32/64X FACS address mismatch in FADT - "
+ "two FACS tables! %8.8X/%8.8X%8.8X",
+ acpi_gbl_FADT.facs,
+ ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xfacs)));
+ }
- for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+ if (acpi_gbl_FADT.dsdt &&
+ (acpi_gbl_FADT.Xdsdt != (u64) acpi_gbl_FADT.dsdt)) {
+ ACPI_WARNING((AE_INFO,
+ "32/64X DSDT address mismatch in FADT - "
+ "two DSDT tables! %8.8X/%8.8X%8.8X",
+ acpi_gbl_FADT.dsdt,
+ ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xdsdt)));
+ }
- /* Generate pointers to the 32-bit and 64-bit addresses and get the length */
+ /* Examine all of the 64-bit extended address fields (X fields) */
- address64 =
- ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
- fadt_info_table[i].target);
+ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+ /*
+ * Generate pointers to the 32-bit and 64-bit addresses, get the
+ * register length (width), and the register name
+ */
+ address64 = ACPI_ADD_PTR(struct acpi_generic_address,
+ &acpi_gbl_FADT,
+ fadt_info_table[i].address64);
address32 =
ACPI_ADD_PTR(u32, &acpi_gbl_FADT,
- fadt_info_table[i].source);
+ fadt_info_table[i].address32);
length =
*ACPI_ADD_PTR(u8, &acpi_gbl_FADT,
fadt_info_table[i].length);
+ name = fadt_info_table[i].name;
+
+ /*
+ * For each extended field, check for length mismatch between the
+ * legacy length field and the corresponding 64-bit X length field.
+ */
+ if (address64 && (address64->bit_width != ACPI_MUL_8(length))) {
+ ACPI_WARNING((AE_INFO,
+ "32/64X length mismatch in %s: %d/%d",
+ name, ACPI_MUL_8(length),
+ address64->bit_width));
+ }
if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) {
/*
@@ -439,8 +575,8 @@ static void acpi_tb_validate_fadt(void)
*/
if (!address64->address || !length) {
ACPI_ERROR((AE_INFO,
- "Required field \"%s\" has zero address and/or length: %8.8X%8.8X/%X",
- fadt_info_table[i].name,
+ "Required field %s has zero address and/or length: %8.8X%8.8X/%X",
+ name,
ACPI_FORMAT_UINT64(address64->
address),
length));
@@ -453,8 +589,8 @@ static void acpi_tb_validate_fadt(void)
if ((address64->address && !length)
|| (!address64->address && length)) {
ACPI_WARNING((AE_INFO,
- "Optional field \"%s\" has zero address or length: %8.8X%8.8X/%X",
- fadt_info_table[i].name,
+ "Optional field %s has zero address or length: %8.8X%8.8X/%X",
+ name,
ACPI_FORMAT_UINT64(address64->
address),
length));
@@ -466,8 +602,8 @@ static void acpi_tb_validate_fadt(void)
if (address64->address && *address32 &&
(address64->address != (u64) * address32)) {
ACPI_ERROR((AE_INFO,
- "32/64X address mismatch in \"%s\": [%8.8X] [%8.8X%8.8X], using 64X",
- fadt_info_table[i].name, *address32,
+ "32/64X address mismatch in %s: %8.8X/%8.8X%8.8X, using 64X",
+ name, *address32,
ACPI_FORMAT_UINT64(address64->address)));
}
}
diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/acpica/tbfind.c
index 531584defbb8..1054dfd49207 100644
--- a/drivers/acpi/tables/tbfind.c
+++ b/drivers/acpi/acpica/tbfind.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "actables.h"
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbfind")
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/acpica/tbinstal.c
index 18747ce8dd2f..37374b21969d 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/acpica/tbinstal.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "actables.h"
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbinstal")
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 0cc92ef5236f..9684cc827930 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "actables.h"
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbutils")
@@ -113,6 +114,30 @@ acpi_tb_check_xsdt(acpi_physical_address address)
/*******************************************************************************
*
+ * FUNCTION: acpi_tb_initialize_facs
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a permanent mapping for the FADT and save it in a global
+ * for accessing the Global Lock and Firmware Waking Vector
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_initialize_facs(void)
+{
+ acpi_status status;
+
+ status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ ACPI_CAST_INDIRECT_PTR(struct
+ acpi_table_header,
+ &acpi_gbl_FACS));
+ return status;
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_tb_tables_loaded
*
* PARAMETERS: None
@@ -420,7 +445,8 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
/* Differentiate between RSDT and XSDT root tables */
- if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
+ if (rsdp->revision > 1 && rsdp->xsdt_physical_address
+ && !acpi_rsdt_forced) {
/*
* Root table is an XSDT (64-bit physical addresses). We must use the
* XSDT if the revision is > 1 and the XSDT pointer is present, as per
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/acpica/tbxface.c
index fd7770aa1061..c3e841f3cde9 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/acpica/tbxface.c
@@ -43,8 +43,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "actables.h"
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbxface")
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c
index 2d157e0f98d2..b7fc8dd43341 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/acpica/tbxfroot.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "actables.h"
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbxfroot")
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/acpica/utalloc.c
index 241c535c1753..7580f6b3069e 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/acpica/utalloc.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acdebug.h>
+#include "accommon.h"
+#include "acdebug.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utalloc")
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/acpica/utcopy.c
index 5b2f7c27b705..b0dcfd3c872a 100644
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/acpica/utcopy.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_UTILITIES
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/acpica/utdebug.c
index fd66ecb6741e..38821f53042c 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/acpica/utdebug.c
@@ -42,6 +42,7 @@
*/
#include <acpi/acpi.h>
+#include "accommon.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utdebug")
@@ -136,7 +137,7 @@ static const char *acpi_ut_trim_function_name(const char *function_name)
/*******************************************************************************
*
- * FUNCTION: acpi_ut_debug_print
+ * FUNCTION: acpi_debug_print
*
* PARAMETERS: requested_debug_level - Requested debug print level
* line_number - Caller's line number (for error output)
@@ -154,11 +155,11 @@ static const char *acpi_ut_trim_function_name(const char *function_name)
******************************************************************************/
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_debug_print(u32 requested_debug_level,
- u32 line_number,
- const char *function_name,
- const char *module_name,
- u32 component_id, const char *format, ...)
+acpi_debug_print(u32 requested_debug_level,
+ u32 line_number,
+ const char *function_name,
+ const char *module_name,
+ u32 component_id, const char *format, ...)
{
acpi_thread_id thread_id;
va_list args;
@@ -205,11 +206,11 @@ acpi_ut_debug_print(u32 requested_debug_level,
va_end(args);
}
-ACPI_EXPORT_SYMBOL(acpi_ut_debug_print)
+ACPI_EXPORT_SYMBOL(acpi_debug_print)
/*******************************************************************************
*
- * FUNCTION: acpi_ut_debug_print_raw
+ * FUNCTION: acpi_debug_print_raw
*
* PARAMETERS: requested_debug_level - Requested debug print level
* line_number - Caller's line number
@@ -226,11 +227,11 @@ ACPI_EXPORT_SYMBOL(acpi_ut_debug_print)
*
******************************************************************************/
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_debug_print_raw(u32 requested_debug_level,
- u32 line_number,
- const char *function_name,
- const char *module_name,
- u32 component_id, const char *format, ...)
+acpi_debug_print_raw(u32 requested_debug_level,
+ u32 line_number,
+ const char *function_name,
+ const char *module_name,
+ u32 component_id, const char *format, ...)
{
va_list args;
@@ -244,7 +245,7 @@ acpi_ut_debug_print_raw(u32 requested_debug_level,
va_end(args);
}
-ACPI_EXPORT_SYMBOL(acpi_ut_debug_print_raw)
+ACPI_EXPORT_SYMBOL(acpi_debug_print_raw)
/*******************************************************************************
*
@@ -270,9 +271,9 @@ acpi_ut_trace(u32 line_number,
acpi_gbl_nesting_level++;
acpi_ut_track_stack_ptr();
- acpi_ut_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name,
- component_id, "%s\n", acpi_gbl_fn_entry_str);
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name, component_id,
+ "%s\n", acpi_gbl_fn_entry_str);
}
ACPI_EXPORT_SYMBOL(acpi_ut_trace)
@@ -301,10 +302,9 @@ acpi_ut_trace_ptr(u32 line_number,
acpi_gbl_nesting_level++;
acpi_ut_track_stack_ptr();
- acpi_ut_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name,
- component_id, "%s %p\n", acpi_gbl_fn_entry_str,
- pointer);
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name, component_id,
+ "%s %p\n", acpi_gbl_fn_entry_str, pointer);
}
/*******************************************************************************
@@ -333,10 +333,9 @@ acpi_ut_trace_str(u32 line_number,
acpi_gbl_nesting_level++;
acpi_ut_track_stack_ptr();
- acpi_ut_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name,
- component_id, "%s %s\n", acpi_gbl_fn_entry_str,
- string);
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name, component_id,
+ "%s %s\n", acpi_gbl_fn_entry_str, string);
}
/*******************************************************************************
@@ -365,10 +364,9 @@ acpi_ut_trace_u32(u32 line_number,
acpi_gbl_nesting_level++;
acpi_ut_track_stack_ptr();
- acpi_ut_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name,
- component_id, "%s %08X\n", acpi_gbl_fn_entry_str,
- integer);
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name, component_id,
+ "%s %08X\n", acpi_gbl_fn_entry_str, integer);
}
/*******************************************************************************
@@ -393,9 +391,9 @@ acpi_ut_exit(u32 line_number,
const char *module_name, u32 component_id)
{
- acpi_ut_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name,
- component_id, "%s\n", acpi_gbl_fn_exit_str);
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name, component_id,
+ "%s\n", acpi_gbl_fn_exit_str);
acpi_gbl_nesting_level--;
}
@@ -426,17 +424,16 @@ acpi_ut_status_exit(u32 line_number,
{
if (ACPI_SUCCESS(status)) {
- acpi_ut_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name,
- component_id, "%s %s\n",
- acpi_gbl_fn_exit_str,
- acpi_format_exception(status));
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name,
+ component_id, "%s %s\n", acpi_gbl_fn_exit_str,
+ acpi_format_exception(status));
} else {
- acpi_ut_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name,
- component_id, "%s ****Exception****: %s\n",
- acpi_gbl_fn_exit_str,
- acpi_format_exception(status));
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name,
+ component_id, "%s ****Exception****: %s\n",
+ acpi_gbl_fn_exit_str,
+ acpi_format_exception(status));
}
acpi_gbl_nesting_level--;
@@ -467,10 +464,10 @@ acpi_ut_value_exit(u32 line_number,
u32 component_id, acpi_integer value)
{
- acpi_ut_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name,
- component_id, "%s %8.8X%8.8X\n",
- acpi_gbl_fn_exit_str, ACPI_FORMAT_UINT64(value));
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name, component_id,
+ "%s %8.8X%8.8X\n", acpi_gbl_fn_exit_str,
+ ACPI_FORMAT_UINT64(value));
acpi_gbl_nesting_level--;
}
@@ -499,9 +496,9 @@ acpi_ut_ptr_exit(u32 line_number,
const char *module_name, u32 component_id, u8 *ptr)
{
- acpi_ut_debug_print(ACPI_LV_FUNCTIONS,
- line_number, function_name, module_name,
- component_id, "%s %p\n", acpi_gbl_fn_exit_str, ptr);
+ acpi_debug_print(ACPI_LV_FUNCTIONS,
+ line_number, function_name, module_name, component_id,
+ "%s %p\n", acpi_gbl_fn_exit_str, ptr);
acpi_gbl_nesting_level--;
}
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/acpica/utdelete.c
index d197c6b29e17..a0be9e39531e 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -42,9 +42,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acinterp.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acevents.h>
+#include "accommon.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#include "acevents.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utdelete")
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/acpica/uteval.c
index 352747e49c7a..da9450bc60f7 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -42,8 +42,9 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acinterp.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acinterp.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("uteval")
@@ -129,7 +130,7 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state)
/* The interface is supported */
- return_ACPI_STATUS(AE_CTRL_TERMINATE);
+ return_ACPI_STATUS(AE_OK);
}
}
@@ -143,13 +144,13 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state)
/* The interface is supported */
- return_ACPI_STATUS(AE_CTRL_TERMINATE);
+ return_ACPI_STATUS(AE_OK);
}
/* The interface is not supported */
return_desc->integer.value = 0;
- return_ACPI_STATUS(AE_CTRL_TERMINATE);
+ return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/acpica/utglobal.c
index 17ed5ac840f7..a3ab9d9da299 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -44,11 +44,11 @@
#define DEFINE_ACPI_GLOBALS
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acnamesp.h"
-ACPI_EXPORT_SYMBOL(acpi_gbl_FADT)
#define _COMPONENT ACPI_UTILITIES
- ACPI_MODULE_NAME("utglobal")
+ACPI_MODULE_NAME("utglobal")
/*******************************************************************************
*
@@ -352,7 +352,7 @@ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = {
"PCI_Config",
"EmbeddedControl",
"SMBus",
- "CMOS",
+ "SystemCMOS",
"PCIBARTarget",
"DataTable"
};
@@ -756,6 +756,7 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_gpe_xrupt_list_head = NULL;
acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL;
+ acpi_current_gpe_count = 0;
/* Global handlers */
@@ -771,6 +772,7 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_global_lock_mutex = NULL;
acpi_gbl_global_lock_acquired = FALSE;
acpi_gbl_global_lock_handle = 0;
+ acpi_gbl_global_lock_present = FALSE;
/* Miscellaneous variables */
@@ -815,5 +817,7 @@ acpi_status acpi_ut_init_globals(void)
return_ACPI_STATUS(AE_OK);
}
+ACPI_EXPORT_SYMBOL(acpi_gbl_FADT)
ACPI_EXPORT_SYMBOL(acpi_dbg_level)
ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
+ACPI_EXPORT_SYMBOL(acpi_current_gpe_count)
diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/acpica/utinit.c
index cae515fc02d3..a54ca84eb362 100644
--- a/drivers/acpi/utilities/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -42,9 +42,10 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acevents.h>
-#include <acpi/actables.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acevents.h"
+#include "actables.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utinit")
diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/acpica/utmath.c
index c927324fdd26..c9f682d640ef 100644
--- a/drivers/acpi/utilities/utmath.c
+++ b/drivers/acpi/acpica/utmath.c
@@ -42,6 +42,7 @@
*/
#include <acpi/acpi.h>
+#include "accommon.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utmath")
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/acpica/utmisc.c
index 9089a158a874..c1f7f4e1a72d 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/acpica/utmisc.c
@@ -44,7 +44,8 @@
#include <linux/module.h>
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utmisc")
@@ -1016,7 +1017,7 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object,
/*******************************************************************************
*
- * FUNCTION: acpi_ut_error, acpi_ut_warning, acpi_ut_info
+ * FUNCTION: acpi_error, acpi_exception, acpi_warning, acpi_info
*
* PARAMETERS: module_name - Caller's module name (for error output)
* line_number - Caller's line number (for error output)
@@ -1029,7 +1030,7 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object,
******************************************************************************/
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_error(const char *module_name, u32 line_number, const char *format, ...)
+acpi_error(const char *module_name, u32 line_number, const char *format, ...)
{
va_list args;
@@ -1042,8 +1043,8 @@ acpi_ut_error(const char *module_name, u32 line_number, const char *format, ...)
}
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_exception(const char *module_name,
- u32 line_number, acpi_status status, const char *format, ...)
+acpi_exception(const char *module_name,
+ u32 line_number, acpi_status status, const char *format, ...)
{
va_list args;
@@ -1056,11 +1057,8 @@ acpi_ut_exception(const char *module_name,
va_end(args);
}
-EXPORT_SYMBOL(acpi_ut_exception);
-
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_warning(const char *module_name,
- u32 line_number, const char *format, ...)
+acpi_warning(const char *module_name, u32 line_number, const char *format, ...)
{
va_list args;
@@ -1073,7 +1071,7 @@ acpi_ut_warning(const char *module_name,
}
void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_info(const char *module_name, u32 line_number, const char *format, ...)
+acpi_info(const char *module_name, u32 line_number, const char *format, ...)
{
va_list args;
@@ -1088,3 +1086,8 @@ acpi_ut_info(const char *module_name, u32 line_number, const char *format, ...)
acpi_os_printf("\n");
va_end(args);
}
+
+ACPI_EXPORT_SYMBOL(acpi_error)
+ACPI_EXPORT_SYMBOL(acpi_exception)
+ACPI_EXPORT_SYMBOL(acpi_warning)
+ACPI_EXPORT_SYMBOL(acpi_info)
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/acpica/utmutex.c
index 7331dde9e1b3..14eb52c4d647 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -42,6 +42,7 @@
*/
#include <acpi/acpi.h>
+#include "accommon.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utmutex")
diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/acpica/utobject.c
index c354e7a42bcd..fd5ea7543e5b 100644
--- a/drivers/acpi/utilities/utobject.c
+++ b/drivers/acpi/acpica/utobject.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
+#include "accommon.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utobject")
@@ -297,7 +298,7 @@ union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size)
*
* RETURN: TRUE if object is valid, FALSE otherwise
*
- * DESCRIPTION: Validate a pointer to be an union acpi_operand_object
+ * DESCRIPTION: Validate a pointer to be a union acpi_operand_object
*
******************************************************************************/
@@ -389,7 +390,7 @@ void acpi_ut_delete_object_desc(union acpi_operand_object *object)
{
ACPI_FUNCTION_TRACE_PTR(ut_delete_object_desc, object);
- /* Object must be an union acpi_operand_object */
+ /* Object must be a union acpi_operand_object */
if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) {
ACPI_ERROR((AE_INFO,
diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/acpica/utresrc.c
index c3e3e1308edc..91b7c00236f4 100644
--- a/drivers/acpi/utilities/utresrc.c
+++ b/drivers/acpi/acpica/utresrc.c
@@ -42,7 +42,8 @@
*/
#include <acpi/acpi.h>
-#include <acpi/amlresrc.h>
+#include "accommon.h"
+#include "amlresrc.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utresrc")
diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/acpica/utstate.c
index 63a6d3d77d88..0440c958f5a4 100644
--- a/drivers/acpi/utilities/utstate.c
+++ b/drivers/acpi/acpica/utstate.c
@@ -42,6 +42,7 @@
*/
#include <acpi/acpi.h>
+#include "accommon.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utstate")
diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/acpica/utxface.c
index c198a4d40583..078a22728c6b 100644
--- a/drivers/acpi/utilities/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -42,9 +42,11 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acevents.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acdebug.h>
+#include "accommon.h"
+#include "acevents.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+#include "actables.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utxface")
@@ -148,6 +150,16 @@ acpi_status acpi_enable_subsystem(u32 flags)
}
/*
+ * Obtain a permanent mapping for the FACS. This is required for the
+ * Global Lock and the Firmware Waking Vector
+ */
+ status = acpi_tb_initialize_facs();
+ if (ACPI_FAILURE(status)) {
+ ACPI_WARNING((AE_INFO, "Could not map the FACS table"));
+ return_ACPI_STATUS(status);
+ }
+
+ /*
* Install the default op_region handlers. These are installed unless
* other handlers have already been installed via the
* install_address_space_handler interface.
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 1423b0c0cd2e..65132f920459 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -471,7 +471,7 @@ static void sysfs_remove_battery(struct acpi_battery *battery)
static int acpi_battery_update(struct acpi_battery *battery)
{
- int result;
+ int result, old_present = acpi_battery_present(battery);
result = acpi_battery_get_status(battery);
if (result)
return result;
@@ -482,7 +482,8 @@ static int acpi_battery_update(struct acpi_battery *battery)
return 0;
}
#endif
- if (!battery->update_time) {
+ if (!battery->update_time ||
+ old_present != acpi_battery_present(battery)) {
result = acpi_battery_get_info(battery);
if (result)
return result;
diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c
index 307963bd1043..332fe4b21708 100644
--- a/drivers/acpi/cm_sbs.c
+++ b/drivers/acpi/cm_sbs.c
@@ -27,9 +27,6 @@
#include <linux/seq_file.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
-#include <acpi/acmacros.h>
-#include <acpi/actypes.h>
-#include <acpi/acutils.h>
ACPI_MODULE_NAME("cm_sbs");
#define ACPI_AC_CLASS "ac_adapter"
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
index c48396892008..20223cbd0d1c 100644
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -9,7 +9,6 @@
#include <linux/moduleparam.h>
#include <asm/uaccess.h>
#include <acpi/acpi_drivers.h>
-#include <acpi/acglobal.h>
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("debug");
diff --git a/drivers/acpi/dispatcher/Makefile b/drivers/acpi/dispatcher/Makefile
deleted file mode 100644
index eb7e602a83cd..000000000000
--- a/drivers/acpi/dispatcher/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for all Linux ACPI interpreter subdirectories
-#
-
-obj-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \
- dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \
- dsinit.o
-
-EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 30f3ef236ecb..a2b82c90a683 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -42,7 +42,6 @@
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
-#include <acpi/actypes.h>
#define ACPI_EC_CLASS "embedded_controller"
#define ACPI_EC_DEVICE_NAME "Embedded Controller"
@@ -121,31 +120,6 @@ static struct acpi_ec {
spinlock_t curr_lock;
} *boot_ec, *first_ec;
-/*
- * Some Asus system have exchanged ECDT data/command IO addresses.
- */
-static int print_ecdt_error(const struct dmi_system_id *id)
-{
- printk(KERN_NOTICE PREFIX "%s detected - "
- "ECDT has exchanged control/data I/O address\n",
- id->ident);
- return 0;
-}
-
-static struct dmi_system_id __cpuinitdata ec_dmi_table[] = {
- {
- print_ecdt_error, "Asus L4R", {
- DMI_MATCH(DMI_BIOS_VERSION, "1008.006"),
- DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),
- DMI_MATCH(DMI_BOARD_NAME, "L4R") }, NULL},
- {
- print_ecdt_error, "Asus M6R", {
- DMI_MATCH(DMI_BIOS_VERSION, "0207"),
- DMI_MATCH(DMI_PRODUCT_NAME, "M6R"),
- DMI_MATCH(DMI_BOARD_NAME, "M6R") }, NULL},
- {},
-};
-
/* --------------------------------------------------------------------------
Transaction Management
-------------------------------------------------------------------------- */
@@ -370,7 +344,7 @@ unlock:
* Note: samsung nv5000 doesn't work with ec burst mode.
* http://bugzilla.kernel.org/show_bug.cgi?id=4980
*/
-int acpi_ec_burst_enable(struct acpi_ec *ec)
+static int acpi_ec_burst_enable(struct acpi_ec *ec)
{
u8 d;
struct transaction t = {.command = ACPI_EC_BURST_ENABLE,
@@ -380,7 +354,7 @@ int acpi_ec_burst_enable(struct acpi_ec *ec)
return acpi_ec_transaction(ec, &t, 0);
}
-int acpi_ec_burst_disable(struct acpi_ec *ec)
+static int acpi_ec_burst_disable(struct acpi_ec *ec)
{
struct transaction t = {.command = ACPI_EC_BURST_DISABLE,
.wdata = NULL, .rdata = NULL,
@@ -756,10 +730,15 @@ static acpi_status
acpi_ec_register_query_methods(acpi_handle handle, u32 level,
void *context, void **return_value)
{
- struct acpi_namespace_node *node = handle;
+ char node_name[5];
+ struct acpi_buffer buffer = { sizeof(node_name), node_name };
struct acpi_ec *ec = context;
int value = 0;
- if (sscanf(node->name.ascii, "_Q%x", &value) == 1) {
+ acpi_status status;
+
+ status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
+
+ if (ACPI_SUCCESS(status) && sscanf(node_name, "_Q%x", &value) == 1) {
acpi_ec_add_query_handler(ec, value, handle, NULL, NULL);
}
return AE_OK;
@@ -978,8 +957,8 @@ static const struct acpi_device_id ec_device_ids[] = {
int __init acpi_ec_ecdt_probe(void)
{
- int ret;
acpi_status status;
+ struct acpi_ec *saved_ec = NULL;
struct acpi_table_ecdt *ecdt_ptr;
boot_ec = make_acpi_ec();
@@ -994,42 +973,55 @@ int __init acpi_ec_ecdt_probe(void)
pr_info(PREFIX "EC description table is found, configuring boot EC\n");
boot_ec->command_addr = ecdt_ptr->control.address;
boot_ec->data_addr = ecdt_ptr->data.address;
- if (dmi_check_system(ec_dmi_table)) {
- /*
- * If the board falls into ec_dmi_table, it means
- * that ECDT table gives the incorrect command/status
- * & data I/O address. Just fix it.
- */
- boot_ec->data_addr = ecdt_ptr->control.address;
- boot_ec->command_addr = ecdt_ptr->data.address;
- }
boot_ec->gpe = ecdt_ptr->gpe;
boot_ec->handle = ACPI_ROOT_OBJECT;
acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle);
+ /* Don't trust ECDT, which comes from ASUSTek */
+ if (!dmi_name_in_vendors("ASUS"))
+ goto install;
+ saved_ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ if (!saved_ec)
+ return -ENOMEM;
+ memcpy(&saved_ec, boot_ec, sizeof(saved_ec));
+ /* fall through */
+ }
+ /* This workaround is needed only on some broken machines,
+ * which require early EC, but fail to provide ECDT */
+ printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n");
+ status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device,
+ boot_ec, NULL);
+ /* Check that acpi_get_devices actually find something */
+ if (ACPI_FAILURE(status) || !boot_ec->handle)
+ goto error;
+ if (saved_ec) {
+ /* try to find good ECDT from ASUSTek */
+ if (saved_ec->command_addr != boot_ec->command_addr ||
+ saved_ec->data_addr != boot_ec->data_addr ||
+ saved_ec->gpe != boot_ec->gpe ||
+ saved_ec->handle != boot_ec->handle)
+ pr_info(PREFIX "ASUSTek keeps feeding us with broken "
+ "ECDT tables, which are very hard to workaround. "
+ "Trying to use DSDT EC info instead. Please send "
+ "output of acpidump to linux-acpi@vger.kernel.org\n");
+ kfree(saved_ec);
+ saved_ec = NULL;
} else {
- /* This workaround is needed only on some broken machines,
- * which require early EC, but fail to provide ECDT */
- acpi_handle x;
- printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n");
- status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device,
- boot_ec, NULL);
- /* Check that acpi_get_devices actually find something */
- if (ACPI_FAILURE(status) || !boot_ec->handle)
- goto error;
/* We really need to limit this workaround, the only ASUS,
- * which needs it, has fake EC._INI method, so use it as flag.
- * Keep boot_ec struct as it will be needed soon.
- */
- if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x)))
+ * which needs it, has fake EC._INI method, so use it as flag.
+ * Keep boot_ec struct as it will be needed soon.
+ */
+ acpi_handle dummy;
+ if (!dmi_name_in_vendors("ASUS") ||
+ ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI",
+ &dummy)))
return -ENODEV;
}
-
- ret = ec_install_handlers(boot_ec);
- if (!ret) {
+install:
+ if (!ec_install_handlers(boot_ec)) {
first_ec = boot_ec;
return 0;
}
- error:
+error:
kfree(boot_ec);
boot_ec = NULL;
return -ENODEV;
diff --git a/drivers/acpi/events/Makefile b/drivers/acpi/events/Makefile
deleted file mode 100644
index d29f2ee449cc..000000000000
--- a/drivers/acpi/events/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for all Linux ACPI interpreter subdirectories
-#
-
-obj-y := evevent.o evregion.o evsci.o evxfevnt.o \
- evmisc.o evrgnini.o evxface.o evxfregn.o \
- evgpe.o evgpeblk.o
-
-EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/executer/Makefile b/drivers/acpi/executer/Makefile
deleted file mode 100644
index e09998aa012f..000000000000
--- a/drivers/acpi/executer/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Makefile for all Linux ACPI interpreter subdirectories
-#
-
-obj-y := exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\
- exconvrt.o exfldio.o exoparg1.o exprep.o exresop.o exsystem.o\
- excreate.o exmisc.o exoparg2.o exregion.o exstore.o exutils.o \
- exdump.o exmutex.o exoparg3.o exresnte.o exstoren.o
-
-EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/hardware/Makefile b/drivers/acpi/hardware/Makefile
deleted file mode 100644
index 438ad373b9ad..000000000000
--- a/drivers/acpi/hardware/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for all Linux ACPI interpreter subdirectories
-#
-
-obj-y := hwacpi.o hwgpe.o hwregs.o hwsleep.o
-
-obj-$(ACPI_FUTURE_USAGE) += hwtimer.o
-
-EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/namespace/Makefile b/drivers/acpi/namespace/Makefile
deleted file mode 100644
index 371a2daf837f..000000000000
--- a/drivers/acpi/namespace/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for all Linux ACPI interpreter subdirectories
-#
-
-obj-y := nsaccess.o nsload.o nssearch.o nsxfeval.o \
- nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \
- nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \
- nsparse.o nspredef.o
-
-obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o
-
-EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 25ceae9191ef..c5e292aab0e3 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -29,7 +29,6 @@
#include <linux/errno.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
-#include <acpi/acmacros.h>
#define ACPI_NUMA 0x80000000
#define _COMPONENT ACPI_NUMA
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index c8111424dcb8..6729a4992f2b 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -726,7 +726,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC);
if (!dpc)
- return_ACPI_STATUS(AE_NO_MEMORY);
+ return AE_NO_MEMORY;
dpc->function = function;
dpc->context = context;
@@ -747,7 +747,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,
status = AE_ERROR;
kfree(dpc);
}
- return_ACPI_STATUS(status);
+ return status;
}
acpi_status acpi_os_execute(acpi_execute_type type,
diff --git a/drivers/acpi/parser/Makefile b/drivers/acpi/parser/Makefile
deleted file mode 100644
index db24ee09cf11..000000000000
--- a/drivers/acpi/parser/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for all Linux ACPI interpreter subdirectories
-#
-
-obj-y := psargs.o psparse.o psloop.o pstree.o pswalk.o \
- psopcode.o psscope.o psutils.o psxface.o
-
-EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
index 4b252ea0e952..95650f83ce2e 100644
--- a/drivers/acpi/pci_bind.c
+++ b/drivers/acpi/pci_bind.c
@@ -99,7 +99,7 @@ acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id)
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Device %s has PCI address %02x:%02x:%02x.%02x\n",
+ "Device %s has PCI address %04x:%02x:%02x.%d\n",
acpi_device_bid(device), id->segment, id->bus,
id->device, id->function));
@@ -111,12 +111,11 @@ EXPORT_SYMBOL(acpi_get_pci_id);
int acpi_pci_bind(struct acpi_device *device)
{
int result = 0;
- acpi_status status = AE_OK;
- struct acpi_pci_data *data = NULL;
- struct acpi_pci_data *pdata = NULL;
- char *pathname = NULL;
- struct acpi_buffer buffer = { 0, NULL };
- acpi_handle handle = NULL;
+ acpi_status status;
+ struct acpi_pci_data *data;
+ struct acpi_pci_data *pdata;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_handle handle;
struct pci_dev *dev;
struct pci_bus *bus;
@@ -124,21 +123,18 @@ int acpi_pci_bind(struct acpi_device *device)
if (!device || !device->parent)
return -EINVAL;
- pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
- if (!pathname)
- return -ENOMEM;
- buffer.length = ACPI_PATHNAME_MAX;
- buffer.pointer = pathname;
-
data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
- if (!data) {
- kfree(pathname);
+ if (!data)
return -ENOMEM;
+
+ status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
+ if (ACPI_FAILURE(status)) {
+ kfree(data);
+ return -ENODEV;
}
- acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n",
- pathname));
+ (char *)buffer.pointer));
/*
* Segment & Bus
@@ -166,7 +162,7 @@ int acpi_pci_bind(struct acpi_device *device)
data->id.device = device->pnp.bus_address >> 16;
data->id.function = device->pnp.bus_address & 0xFFFF;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %02x:%02x:%02x.%02x\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %04x:%02x:%02x.%d\n",
data->id.segment, data->id.bus, data->id.device,
data->id.function));
@@ -196,7 +192,7 @@ int acpi_pci_bind(struct acpi_device *device)
}
if (!data->dev) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Device %02x:%02x:%02x.%02x not present in PCI namespace\n",
+ "Device %04x:%02x:%02x.%d not present in PCI namespace\n",
data->id.segment, data->id.bus,
data->id.device, data->id.function));
result = -ENODEV;
@@ -204,7 +200,7 @@ int acpi_pci_bind(struct acpi_device *device)
}
if (!data->dev->bus) {
printk(KERN_ERR PREFIX
- "Device %02x:%02x:%02x.%02x has invalid 'bus' field\n",
+ "Device %04x:%02x:%02x.%d has invalid 'bus' field\n",
data->id.segment, data->id.bus,
data->id.device, data->id.function);
result = -ENODEV;
@@ -219,7 +215,7 @@ int acpi_pci_bind(struct acpi_device *device)
*/
if (data->dev->subordinate) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Device %02x:%02x:%02x.%02x is a PCI bridge\n",
+ "Device %04x:%02x:%02x.%d is a PCI bridge\n",
data->id.segment, data->id.bus,
data->id.device, data->id.function));
data->bus = data->dev->subordinate;
@@ -262,7 +258,7 @@ int acpi_pci_bind(struct acpi_device *device)
}
end:
- kfree(pathname);
+ kfree(buffer.pointer);
if (result)
kfree(data);
@@ -272,25 +268,21 @@ int acpi_pci_bind(struct acpi_device *device)
static int acpi_pci_unbind(struct acpi_device *device)
{
int result = 0;
- acpi_status status = AE_OK;
- struct acpi_pci_data *data = NULL;
- char *pathname = NULL;
- struct acpi_buffer buffer = { 0, NULL };
+ acpi_status status;
+ struct acpi_pci_data *data;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
if (!device || !device->parent)
return -EINVAL;
- pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
- if (!pathname)
- return -ENOMEM;
+ status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
- buffer.length = ACPI_PATHNAME_MAX;
- buffer.pointer = pathname;
- acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n",
- pathname));
- kfree(pathname);
+ (char *) buffer.pointer));
+ kfree(buffer.pointer);
status =
acpi_get_data(device->handle, acpi_pci_data_handler,
@@ -322,50 +314,44 @@ acpi_pci_bind_root(struct acpi_device *device,
struct acpi_pci_id *id, struct pci_bus *bus)
{
int result = 0;
- acpi_status status = AE_OK;
+ acpi_status status;
struct acpi_pci_data *data = NULL;
- char *pathname = NULL;
- struct acpi_buffer buffer = { 0, NULL };
-
- pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
- if (!pathname)
- return -ENOMEM;
-
- buffer.length = ACPI_PATHNAME_MAX;
- buffer.pointer = pathname;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
if (!device || !id || !bus) {
- kfree(pathname);
return -EINVAL;
}
data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
- if (!data) {
- kfree(pathname);
+ if (!data)
return -ENOMEM;
- }
data->id = *id;
data->bus = bus;
device->ops.bind = acpi_pci_bind;
device->ops.unbind = acpi_pci_unbind;
- acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
+ status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
+ if (ACPI_FAILURE(status)) {
+ kfree (data);
+ return -ENODEV;
+ }
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI root bridge [%s] to "
- "%02x:%02x\n", pathname, id->segment, id->bus));
+ "%04x:%02x\n", (char *)buffer.pointer,
+ id->segment, id->bus));
status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Unable to attach ACPI-PCI context to device %s",
- pathname));
+ (char *)buffer.pointer));
result = -ENODEV;
goto end;
}
end:
- kfree(pathname);
+ kfree(buffer.pointer);
if (result != 0)
kfree(data);
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index bf79d83bdfbb..891bdf6679f3 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -4,6 +4,8 @@
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
* Copyright (C) 2002 Dominik Brodowski <devel@brodo.de>
+ * (c) Copyright 2008 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -41,29 +43,36 @@
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_irq");
-static struct acpi_prt_list acpi_prt;
+struct acpi_prt_entry {
+ struct list_head list;
+ struct acpi_pci_id id;
+ u8 pin;
+ acpi_handle link;
+ u32 index; /* GSI, or link _CRS index */
+};
+
+static LIST_HEAD(acpi_prt_list);
static DEFINE_SPINLOCK(acpi_prt_lock);
+static inline char pin_name(int pin)
+{
+ return 'A' + pin - 1;
+}
+
/* --------------------------------------------------------------------------
PCI IRQ Routing Table (PRT) Support
-------------------------------------------------------------------------- */
-static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
- int bus,
- int device, int pin)
+static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev,
+ int pin)
{
- struct acpi_prt_entry *entry = NULL;
-
- if (!acpi_prt.count)
- return NULL;
+ struct acpi_prt_entry *entry;
+ int segment = pci_domain_nr(dev->bus);
+ int bus = dev->bus->number;
+ int device = PCI_SLOT(dev->devfn);
- /*
- * Parse through all PRT entries looking for a match on the specified
- * PCI device's segment, bus, device, and pin (don't care about func).
- *
- */
spin_lock(&acpi_prt_lock);
- list_for_each_entry(entry, &acpi_prt.entries, node) {
+ list_for_each_entry(entry, &acpi_prt_list, list) {
if ((segment == entry->id.segment)
&& (bus == entry->id.bus)
&& (device == entry->id.device)
@@ -72,7 +81,6 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
return entry;
}
}
-
spin_unlock(&acpi_prt_lock);
return NULL;
}
@@ -124,25 +132,27 @@ struct prt_quirk {
char *actual_source;
};
+#define PCI_INTX_PIN(c) (c - 'A' + 1)
+
/*
* These systems have incorrect _PRT entries. The BIOS claims the PCI
* interrupt at the listed segment/bus/device/pin is connected to the first
* link device, but it is actually connected to the second.
*/
static struct prt_quirk prt_quirks[] = {
- { medion_md9580, 0, 0, 9, 'A',
+ { medion_md9580, 0, 0, 9, PCI_INTX_PIN('A'),
"\\_SB_.PCI0.ISA_.LNKA",
"\\_SB_.PCI0.ISA_.LNKB"},
- { dell_optiplex, 0, 0, 0xd, 'A',
+ { dell_optiplex, 0, 0, 0xd, PCI_INTX_PIN('A'),
"\\_SB_.LNKB",
"\\_SB_.LNKA"},
- { hp_t5710, 0, 0, 1, 'A',
+ { hp_t5710, 0, 0, 1, PCI_INTX_PIN('A'),
"\\_SB_.PCI0.LNK1",
"\\_SB_.PCI0.LNK3"},
};
-static void
-do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt)
+static void do_prt_fixups(struct acpi_prt_entry *entry,
+ struct acpi_pci_routing_table *prt)
{
int i;
struct prt_quirk *quirk;
@@ -158,42 +168,43 @@ do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt)
entry->id.segment == quirk->segment &&
entry->id.bus == quirk->bus &&
entry->id.device == quirk->device &&
- entry->pin + 'A' == quirk->pin &&
+ entry->pin == quirk->pin &&
!strcmp(prt->source, quirk->source) &&
strlen(prt->source) >= strlen(quirk->actual_source)) {
printk(KERN_WARNING PREFIX "firmware reports "
"%04x:%02x:%02x PCI INT %c connected to %s; "
"changing to %s\n",
entry->id.segment, entry->id.bus,
- entry->id.device, 'A' + entry->pin,
+ entry->id.device, pin_name(entry->pin),
prt->source, quirk->actual_source);
strcpy(prt->source, quirk->actual_source);
}
}
}
-static int
-acpi_pci_irq_add_entry(acpi_handle handle,
- int segment, int bus, struct acpi_pci_routing_table *prt)
+static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus,
+ struct acpi_pci_routing_table *prt)
{
- struct acpi_prt_entry *entry = NULL;
-
-
- if (!prt)
- return -EINVAL;
+ struct acpi_prt_entry *entry;
entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
+ /*
+ * Note that the _PRT uses 0=INTA, 1=INTB, etc, while PCI uses
+ * 1=INTA, 2=INTB. We use the PCI encoding throughout, so convert
+ * it here.
+ */
entry->id.segment = segment;
entry->id.bus = bus;
entry->id.device = (prt->address >> 16) & 0xFFFF;
- entry->id.function = prt->address & 0xFFFF;
- entry->pin = prt->pin;
+ entry->pin = prt->pin + 1;
do_prt_fixups(entry, prt);
+ entry->index = prt->source_index;
+
/*
* Type 1: Dynamic
* ---------------
@@ -207,10 +218,9 @@ acpi_pci_irq_add_entry(acpi_handle handle,
* (e.g. exists somewhere 'below' this _PRT entry in the ACPI
* namespace).
*/
- if (prt->source[0]) {
- acpi_get_handle(handle, prt->source, &entry->link.handle);
- entry->link.index = prt->source_index;
- }
+ if (prt->source[0])
+ acpi_get_handle(handle, prt->source, &entry->link);
+
/*
* Type 2: Static
* --------------
@@ -218,84 +228,38 @@ acpi_pci_irq_add_entry(acpi_handle handle,
* the IRQ value, which is hardwired to specific interrupt inputs on
* the interrupt controller.
*/
- else
- entry->link.index = prt->source_index;
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,
- " %02X:%02X:%02X[%c] -> %s[%d]\n",
+ " %04x:%02x:%02x[%c] -> %s[%d]\n",
entry->id.segment, entry->id.bus,
- entry->id.device, ('A' + entry->pin), prt->source,
- entry->link.index));
+ entry->id.device, pin_name(entry->pin),
+ prt->source, entry->index));
spin_lock(&acpi_prt_lock);
- list_add_tail(&entry->node, &acpi_prt.entries);
- acpi_prt.count++;
+ list_add_tail(&entry->list, &acpi_prt_list);
spin_unlock(&acpi_prt_lock);
return 0;
}
-static void
-acpi_pci_irq_del_entry(int segment, int bus, struct acpi_prt_entry *entry)
-{
- if (segment == entry->id.segment && bus == entry->id.bus) {
- acpi_prt.count--;
- list_del(&entry->node);
- kfree(entry);
- }
-}
-
int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
{
- acpi_status status = AE_OK;
- char *pathname = NULL;
- struct acpi_buffer buffer = { 0, NULL };
- struct acpi_pci_routing_table *prt = NULL;
- struct acpi_pci_routing_table *entry = NULL;
- static int first_time = 1;
-
-
- pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
- if (!pathname)
- return -ENOMEM;
-
- if (first_time) {
- acpi_prt.count = 0;
- INIT_LIST_HEAD(&acpi_prt.entries);
- first_time = 0;
- }
-
- /*
- * NOTE: We're given a 'handle' to the _PRT object's parent device
- * (either a PCI root bridge or PCI-PCI bridge).
- */
+ acpi_status status;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_pci_routing_table *entry;
- buffer.length = ACPI_PATHNAME_MAX;
- buffer.pointer = pathname;
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ /* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */
+ status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n",
- pathname);
+ (char *) buffer.pointer);
- /*
- * Evaluate this _PRT and add its entries to our global list (acpi_prt).
- */
+ kfree(buffer.pointer);
- buffer.length = 0;
+ buffer.length = ACPI_ALLOCATE_BUFFER;
buffer.pointer = NULL;
- kfree(pathname);
- status = acpi_get_irq_routing_table(handle, &buffer);
- if (status != AE_BUFFER_OVERFLOW) {
- ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]",
- acpi_format_exception(status)));
- return -ENODEV;
- }
-
- prt = kzalloc(buffer.length, GFP_KERNEL);
- if (!prt) {
- return -ENOMEM;
- }
- buffer.pointer = prt;
status = acpi_get_irq_routing_table(handle, &buffer);
if (ACPI_FAILURE(status)) {
@@ -305,36 +269,30 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
return -ENODEV;
}
- entry = prt;
-
+ entry = buffer.pointer;
while (entry && (entry->length > 0)) {
acpi_pci_irq_add_entry(handle, segment, bus, entry);
entry = (struct acpi_pci_routing_table *)
((unsigned long)entry + entry->length);
}
- kfree(prt);
-
+ kfree(buffer.pointer);
return 0;
}
void acpi_pci_irq_del_prt(int segment, int bus)
{
- struct list_head *node = NULL, *n = NULL;
- struct acpi_prt_entry *entry = NULL;
-
- if (!acpi_prt.count) {
- return;
- }
+ struct acpi_prt_entry *entry, *tmp;
printk(KERN_DEBUG
- "ACPI: Delete PCI Interrupt Routing Table for %x:%x\n", segment,
- bus);
+ "ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n",
+ segment, bus);
spin_lock(&acpi_prt_lock);
- list_for_each_safe(node, n, &acpi_prt.entries) {
- entry = list_entry(node, struct acpi_prt_entry, node);
-
- acpi_pci_irq_del_entry(segment, bus, entry);
+ list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) {
+ if (segment == entry->id.segment && bus == entry->id.bus) {
+ list_del(&entry->list);
+ kfree(entry);
+ }
}
spin_unlock(&acpi_prt_lock);
}
@@ -342,162 +300,26 @@ void acpi_pci_irq_del_prt(int segment, int bus)
/* --------------------------------------------------------------------------
PCI Interrupt Routing Support
-------------------------------------------------------------------------- */
-typedef int (*irq_lookup_func) (struct acpi_prt_entry *, int *, int *, char **);
-
-static int
-acpi_pci_allocate_irq(struct acpi_prt_entry *entry,
- int *triggering, int *polarity, char **link)
-{
- int irq;
-
-
- if (entry->link.handle) {
- irq = acpi_pci_link_allocate_irq(entry->link.handle,
- entry->link.index, triggering,
- polarity, link);
- if (irq < 0) {
- printk(KERN_WARNING PREFIX
- "Invalid IRQ link routing entry\n");
- return -1;
- }
- } else {
- irq = entry->link.index;
- *triggering = ACPI_LEVEL_SENSITIVE;
- *polarity = ACPI_ACTIVE_LOW;
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq));
- return irq;
-}
-
-static int
-acpi_pci_free_irq(struct acpi_prt_entry *entry,
- int *triggering, int *polarity, char **link)
-{
- int irq;
-
- if (entry->link.handle) {
- irq = acpi_pci_link_free_irq(entry->link.handle);
- } else {
- irq = entry->link.index;
- }
- return irq;
-}
-
-#ifdef CONFIG_X86_IO_APIC
-extern int noioapicquirk;
-
-static int bridge_has_boot_interrupt_variant(struct pci_bus *bus)
+static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
{
- struct pci_bus *bus_it;
-
- for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) {
- if (!bus_it->self)
- return 0;
-
- printk(KERN_INFO "vendor=%04x device=%04x\n", bus_it->self->vendor,
- bus_it->self->device);
-
- if (bus_it->self->irq_reroute_variant)
- return bus_it->self->irq_reroute_variant;
- }
- return 0;
-}
-#endif /* CONFIG_X86_IO_APIC */
-
-/*
- * acpi_pci_irq_lookup
- * success: return IRQ >= 0
- * failure: return -1
- */
-static int
-acpi_pci_irq_lookup(struct pci_bus *bus,
- int device,
- int pin,
- int *triggering,
- int *polarity, char **link, irq_lookup_func func)
-{
- struct acpi_prt_entry *entry = NULL;
- int segment = pci_domain_nr(bus);
- int bus_nr = bus->number;
- int ret;
-
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Searching for PRT entry for %02x:%02x:%02x[%c]\n",
- segment, bus_nr, device, ('A' + pin)));
-
- entry = acpi_pci_irq_find_prt_entry(segment, bus_nr, device, pin);
- if (!entry) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n"));
- return -1;
- }
-
- ret = func(entry, triggering, polarity, link);
-
-#ifdef CONFIG_X86_IO_APIC
- /*
- * Some chipsets (e.g. intel 6700PXH) generate a legacy INTx when the
- * IRQ entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel
- * does during interrupt handling). When this INTx generation cannot be
- * disabled, we reroute these interrupts to their legacy equivalent to
- * get rid of spurious interrupts.
- */
- if (!noioapicquirk) {
- switch (bridge_has_boot_interrupt_variant(bus)) {
- case 0:
- /* no rerouting necessary */
- break;
-
- case INTEL_IRQ_REROUTE_VARIANT:
- /*
- * Remap according to INTx routing table in 6700PXH
- * specs, intel order number 302628-002, section
- * 2.15.2. Other chipsets (80332, ...) have the same
- * mapping and are handled here as well.
- */
- printk(KERN_INFO "pci irq %d -> rerouted to legacy "
- "irq %d\n", ret, (ret % 4) + 16);
- ret = (ret % 4) + 16;
- break;
-
- default:
- printk(KERN_INFO "not rerouting irq %d to legacy irq: "
- "unknown mapping\n", ret);
- break;
- }
+ struct acpi_prt_entry *entry;
+ struct pci_dev *bridge;
+ u8 bridge_pin, orig_pin = pin;
+
+ entry = acpi_pci_irq_find_prt_entry(dev, pin);
+ if (entry) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n",
+ pci_name(dev), pin_name(pin)));
+ return entry;
}
-#endif /* CONFIG_X86_IO_APIC */
-
- return ret;
-}
-
-/*
- * acpi_pci_irq_derive
- * success: return IRQ >= 0
- * failure: return < 0
- */
-static int
-acpi_pci_irq_derive(struct pci_dev *dev,
- int pin,
- int *triggering,
- int *polarity, char **link, irq_lookup_func func)
-{
- struct pci_dev *bridge = dev;
- int irq = -1;
- u8 bridge_pin = 0, orig_pin = pin;
-
-
- if (!dev)
- return -EINVAL;
/*
* Attempt to derive an IRQ for this device from a parent bridge's
* PCI interrupt routing entry (eg. yenta bridge and add-in card bridge).
*/
- while (irq < 0 && bridge->bus->self) {
- pin = (pin + PCI_SLOT(bridge->devfn)) % 4;
- bridge = bridge->bus->self;
+ bridge = dev->bus->self;
+ while (bridge) {
+ pin = (((pin - 1) + PCI_SLOT(dev->devfn)) % 4) + 1;
if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
/* PC card has the same IRQ as its cardbridge */
@@ -506,50 +328,40 @@ acpi_pci_irq_derive(struct pci_dev *dev,
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No interrupt pin configured for device %s\n",
pci_name(bridge)));
- return -1;
+ return NULL;
}
- /* Pin is from 0 to 3 */
- bridge_pin--;
pin = bridge_pin;
}
- irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn),
- pin, triggering, polarity,
- link, func);
- }
+ entry = acpi_pci_irq_find_prt_entry(bridge, pin);
+ if (entry) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Derived GSI for %s INT %c from %s\n",
+ pci_name(dev), pin_name(orig_pin),
+ pci_name(bridge)));
+ return entry;
+ }
- if (irq < 0) {
- dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n",
- 'A' + orig_pin);
- return -1;
+ dev = bridge;
+ bridge = dev->bus->self;
}
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derive IRQ %d for device %s from %s\n",
- irq, pci_name(dev), pci_name(bridge)));
-
- return irq;
+ dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n",
+ pin_name(orig_pin));
+ return NULL;
}
-/*
- * acpi_pci_irq_enable
- * success: return 0
- * failure: return < 0
- */
-
int acpi_pci_irq_enable(struct pci_dev *dev)
{
- int irq = 0;
- u8 pin = 0;
+ struct acpi_prt_entry *entry;
+ int gsi;
+ u8 pin;
int triggering = ACPI_LEVEL_SENSITIVE;
int polarity = ACPI_ACTIVE_LOW;
char *link = NULL;
char link_desc[16];
int rc;
-
- if (!dev)
- return -EINVAL;
-
pin = dev->pin;
if (!pin) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -557,31 +369,9 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
pci_name(dev)));
return 0;
}
- pin--;
-
- if (!dev->bus) {
- dev_err(&dev->dev, "invalid (NULL) 'bus' field\n");
- return -ENODEV;
- }
-
- /*
- * First we check the PCI IRQ routing table (PRT) for an IRQ. PRT
- * values override any BIOS-assigned IRQs set during boot.
- */
- irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
- &triggering, &polarity, &link,
- acpi_pci_allocate_irq);
-
- /*
- * If no PRT entry was found, we'll try to derive an IRQ from the
- * device's parent bridge.
- */
- if (irq < 0)
- irq = acpi_pci_irq_derive(dev, pin, &triggering,
- &polarity, &link,
- acpi_pci_allocate_irq);
- if (irq < 0) {
+ entry = acpi_pci_irq_lookup(dev, pin);
+ if (!entry) {
/*
* IDE legacy mode controller IRQs are magic. Why do compat
* extensions always make such a nasty mess.
@@ -590,12 +380,24 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
(dev->class & 0x05) == 0)
return 0;
}
+
+ if (entry) {
+ if (entry->link)
+ gsi = acpi_pci_link_allocate_irq(entry->link,
+ entry->index,
+ &triggering, &polarity,
+ &link);
+ else
+ gsi = entry->index;
+ } else
+ gsi = -1;
+
/*
* No IRQ known to the ACPI subsystem - maybe the BIOS /
* driver reported one, then use it. Exit in any case.
*/
- if (irq < 0) {
- dev_warn(&dev->dev, "PCI INT %c: no GSI", 'A' + pin);
+ if (gsi < 0) {
+ dev_warn(&dev->dev, "PCI INT %c: no GSI", pin_name(pin));
/* Interrupt Line values above 0xF are forbidden */
if (dev->irq > 0 && (dev->irq <= 0xF)) {
printk(" - using IRQ %d\n", dev->irq);
@@ -608,10 +410,10 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
}
}
- rc = acpi_register_gsi(irq, triggering, polarity);
+ rc = acpi_register_gsi(gsi, triggering, polarity);
if (rc < 0) {
dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n",
- 'A' + pin);
+ pin_name(pin));
return rc;
}
dev->irq = rc;
@@ -622,7 +424,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
link_desc[0] = '\0';
dev_info(&dev->dev, "PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n",
- 'A' + pin, link_desc, irq,
+ pin_name(pin), link_desc, gsi,
(triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
(polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
@@ -636,42 +438,28 @@ void __attribute__ ((weak)) acpi_unregister_gsi(u32 i)
void acpi_pci_irq_disable(struct pci_dev *dev)
{
- int gsi = 0;
- u8 pin = 0;
- int triggering = ACPI_LEVEL_SENSITIVE;
- int polarity = ACPI_ACTIVE_LOW;
-
-
- if (!dev || !dev->bus)
- return;
+ struct acpi_prt_entry *entry;
+ int gsi;
+ u8 pin;
pin = dev->pin;
if (!pin)
return;
- pin--;
- /*
- * First we check the PCI IRQ routing table (PRT) for an IRQ.
- */
- gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
- &triggering, &polarity, NULL,
- acpi_pci_free_irq);
- /*
- * If no PRT entry was found, we'll try to derive an IRQ from the
- * device's parent bridge.
- */
- if (gsi < 0)
- gsi = acpi_pci_irq_derive(dev, pin,
- &triggering, &polarity, NULL,
- acpi_pci_free_irq);
- if (gsi < 0)
+ entry = acpi_pci_irq_lookup(dev, pin);
+ if (!entry)
return;
+ if (entry->link)
+ gsi = acpi_pci_link_free_irq(entry->link);
+ else
+ gsi = entry->index;
+
/*
* TBD: It might be worth clearing dev->irq by magic constant
* (e.g. PCI_UNDEFINED_IRQ).
*/
- dev_info(&dev->dev, "PCI INT %c disabled\n", 'A' + pin);
+ dev_info(&dev->dev, "PCI INT %c disabled\n", pin_name(pin));
acpi_unregister_gsi(gsi);
}
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index e52ad91ce2dc..1c6e73c7865e 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -796,10 +796,6 @@ static int irqrouter_resume(struct sys_device *dev)
struct list_head *node = NULL;
struct acpi_pci_link *link = NULL;
-
- /* Make sure SCI is enabled again (Apple firmware bug?) */
- acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1);
-
list_for_each(node, &acpi_link.entries) {
link = list_entry(node, struct acpi_pci_link, node);
if (!link) {
@@ -912,7 +908,7 @@ static int __init acpi_irq_nobalance_set(char *str)
__setup("acpi_irq_nobalance", acpi_irq_nobalance_set);
-int __init acpi_irq_balance_set(char *str)
+static int __init acpi_irq_balance_set(char *str)
{
acpi_irq_balance = 1;
return 1;
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 642554b1b60c..5b38a026d122 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -31,6 +31,7 @@
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/pci.h>
+#include <linux/pci-acpi.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -193,6 +194,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
unsigned long long value = 0;
acpi_handle handle = NULL;
struct acpi_device *child;
+ u32 flags, base_flags;
if (!device)
@@ -210,6 +212,13 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
device->ops.bind = acpi_pci_bind;
+ /*
+ * All supported architectures that use ACPI have support for
+ * PCI domains, so we indicate this in _OSC support capabilities.
+ */
+ flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
+ pci_acpi_osc_support(device->handle, flags);
+
/*
* Segment
* -------
@@ -335,6 +344,17 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
list_for_each_entry(child, &device->children, node)
acpi_pci_bridge_scan(child);
+ /* Indicate support for various _OSC capabilities. */
+ if (pci_ext_cfg_avail(root->bus->self))
+ flags |= OSC_EXT_PCI_CONFIG_SUPPORT;
+ if (pcie_aspm_enabled())
+ flags |= OSC_ACTIVE_STATE_PWR_SUPPORT |
+ OSC_CLOCK_PWR_CAPABILITY_SUPPORT;
+ if (pci_msi_enabled())
+ flags |= OSC_MSI_SUPPORT;
+ if (flags != base_flags)
+ pci_acpi_osc_support(device->handle, flags);
+
end:
if (result) {
if (!list_empty(&root->node))
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index bb7d50dd2818..c926e7d4a0d6 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -139,6 +139,8 @@ static int acpi_power_get_state(acpi_handle handle, int *state)
{
acpi_status status = AE_OK;
unsigned long long sta = 0;
+ char node_name[5];
+ struct acpi_buffer buffer = { sizeof(node_name), node_name };
if (!handle || !state)
@@ -151,8 +153,10 @@ static int acpi_power_get_state(acpi_handle handle, int *state)
*state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON:
ACPI_POWER_RESOURCE_STATE_OFF;
+ acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n",
- acpi_ut_get_node_name(handle),
+ node_name,
*state ? "on" : "off"));
return 0;
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/proc.c
index 4dbc2271acf5..428c911dba08 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/proc.c
@@ -28,8 +28,6 @@ static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset)
{
int i;
- ACPI_FUNCTION_TRACE("acpi_system_sleep_seq_show");
-
for (i = 0; i <= ACPI_STATE_S5; i++) {
if (sleep_states[i]) {
seq_printf(seq, "S%d ", i);
@@ -86,49 +84,44 @@ acpi_system_write_sleep(struct file *file,
#ifdef HAVE_ACPI_LEGACY_ALARM
+static u32 cmos_bcd_read(int offset, int rtc_control);
+
static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
{
u32 sec, min, hr;
u32 day, mo, yr, cent = 0;
+ u32 today = 0;
unsigned char rtc_control = 0;
unsigned long flags;
- ACPI_FUNCTION_TRACE("acpi_system_alarm_seq_show");
-
spin_lock_irqsave(&rtc_lock, flags);
- sec = CMOS_READ(RTC_SECONDS_ALARM);
- min = CMOS_READ(RTC_MINUTES_ALARM);
- hr = CMOS_READ(RTC_HOURS_ALARM);
rtc_control = CMOS_READ(RTC_CONTROL);
+ sec = cmos_bcd_read(RTC_SECONDS_ALARM, rtc_control);
+ min = cmos_bcd_read(RTC_MINUTES_ALARM, rtc_control);
+ hr = cmos_bcd_read(RTC_HOURS_ALARM, rtc_control);
/* If we ever get an FACP with proper values... */
- if (acpi_gbl_FADT.day_alarm)
+ if (acpi_gbl_FADT.day_alarm) {
/* ACPI spec: only low 6 its should be cared */
day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F;
- else
- day = CMOS_READ(RTC_DAY_OF_MONTH);
+ if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ day = bcd2bin(day);
+ } else
+ day = cmos_bcd_read(RTC_DAY_OF_MONTH, rtc_control);
if (acpi_gbl_FADT.month_alarm)
- mo = CMOS_READ(acpi_gbl_FADT.month_alarm);
- else
- mo = CMOS_READ(RTC_MONTH);
+ mo = cmos_bcd_read(acpi_gbl_FADT.month_alarm, rtc_control);
+ else {
+ mo = cmos_bcd_read(RTC_MONTH, rtc_control);
+ today = cmos_bcd_read(RTC_DAY_OF_MONTH, rtc_control);
+ }
if (acpi_gbl_FADT.century)
- cent = CMOS_READ(acpi_gbl_FADT.century);
+ cent = cmos_bcd_read(acpi_gbl_FADT.century, rtc_control);
- yr = CMOS_READ(RTC_YEAR);
+ yr = cmos_bcd_read(RTC_YEAR, rtc_control);
spin_unlock_irqrestore(&rtc_lock, flags);
- if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- sec = bcd2bin(sec);
- min = bcd2bin(min);
- hr = bcd2bin(hr);
- day = bcd2bin(day);
- mo = bcd2bin(mo);
- yr = bcd2bin(yr);
- cent = bcd2bin(cent);
- }
-
/* we're trusting the FADT (see above) */
if (!acpi_gbl_FADT.century)
/* If we're not trusting the FADT, we should at least make it
@@ -153,6 +146,20 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
else
yr += cent * 100;
+ /*
+ * Show correct dates for alarms up to a month into the future.
+ * This solves issues for nearly all situations with the common
+ * 30-day alarm clocks in PC hardware.
+ */
+ if (day < today) {
+ if (mo < 12) {
+ mo += 1;
+ } else {
+ mo = 1;
+ yr += 1;
+ }
+ }
+
seq_printf(seq, "%4.4u-", yr);
(mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo);
(day > 31) ? seq_puts(seq, "** ") : seq_printf(seq, "%2.2u ", day);
@@ -227,13 +234,11 @@ acpi_system_write_alarm(struct file *file,
int adjust = 0;
unsigned char rtc_control = 0;
- ACPI_FUNCTION_TRACE("acpi_system_write_alarm");
-
if (count > sizeof(alarm_string) - 1)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (copy_from_user(alarm_string, buffer, count))
- return_VALUE(-EFAULT);
+ return -EFAULT;
alarm_string[count] = '\0';
@@ -334,7 +339,7 @@ acpi_system_write_alarm(struct file *file,
result = 0;
end:
- return_VALUE(result ? result : count);
+ return result ? result : count;
}
#endif /* HAVE_ACPI_LEGACY_ALARM */
diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c
index a6b662c00b67..93f91142d7ad 100644
--- a/drivers/acpi/reboot.c
+++ b/drivers/acpi/reboot.c
@@ -42,7 +42,7 @@ void acpi_reboot(void)
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
case ACPI_ADR_SPACE_SYSTEM_IO:
printk(KERN_DEBUG "ACPI MEMORY or I/O RESET_REG.\n");
- acpi_hw_low_level_write(8, reset_value, rr);
+ acpi_reset();
break;
}
/* Wait ten seconds */
diff --git a/drivers/acpi/resources/Makefile b/drivers/acpi/resources/Makefile
deleted file mode 100644
index 8de4f69dfa09..000000000000
--- a/drivers/acpi/resources/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Makefile for all Linux ACPI interpreter subdirectories
-#
-
-obj-y := rsaddr.o rscreate.o rsinfo.o rsio.o rslist.o rsmisc.o rsxface.o \
- rscalc.o rsirq.o rsmemory.o rsutils.o
-
-obj-$(ACPI_FUTURE_USAGE) += rsdump.o
-
-EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index e53e590252c0..0619734895b2 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -10,7 +10,6 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
-#include <acpi/actypes.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 39b7233c3485..c54d7b6c4066 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -10,7 +10,6 @@
#include <linux/kthread.h>
#include <acpi/acpi_drivers.h>
-#include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */
#define _COMPONENT ACPI_BUS_COMPONENT
ACPI_MODULE_NAME("scan");
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep.c
index 28a691cc625e..7e3c609cbef2 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep.c
@@ -101,13 +101,26 @@ void __init acpi_old_suspend_ordering(void)
* cases.
*/
static bool set_sci_en_on_resume;
+/*
+ * The ACPI specification wants us to save NVS memory regions during hibernation
+ * and to restore them during the subsequent resume. However, it is not certain
+ * if this mechanism is going to work on all machines, so we allow the user to
+ * disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line
+ * option.
+ */
+static bool s4_no_nvs;
+
+void __init acpi_s4_no_nvs(void)
+{
+ s4_no_nvs = true;
+}
/**
* acpi_pm_disable_gpes - Disable the GPEs.
*/
static int acpi_pm_disable_gpes(void)
{
- acpi_hw_disable_all_gpes();
+ acpi_disable_all_gpes();
return 0;
}
@@ -135,7 +148,7 @@ static int acpi_pm_prepare(void)
int error = __acpi_pm_prepare();
if (!error)
- acpi_hw_disable_all_gpes();
+ acpi_disable_all_gpes();
return error;
}
@@ -267,7 +280,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
* (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
* acpi_leave_sleep_state will reenable specific GPEs later
*/
- acpi_hw_disable_all_gpes();
+ acpi_disable_all_gpes();
local_irq_restore(flags);
printk(KERN_DEBUG "Back to C!\n");
@@ -394,9 +407,25 @@ void __init acpi_no_s4_hw_signature(void)
static int acpi_hibernation_begin(void)
{
- acpi_target_sleep_state = ACPI_STATE_S4;
- acpi_sleep_tts_switch(acpi_target_sleep_state);
- return 0;
+ int error;
+
+ error = s4_no_nvs ? 0 : hibernate_nvs_alloc();
+ if (!error) {
+ acpi_target_sleep_state = ACPI_STATE_S4;
+ acpi_sleep_tts_switch(acpi_target_sleep_state);
+ }
+
+ return error;
+}
+
+static int acpi_hibernation_pre_snapshot(void)
+{
+ int error = acpi_pm_prepare();
+
+ if (!error)
+ hibernate_nvs_save();
+
+ return error;
}
static int acpi_hibernation_enter(void)
@@ -417,6 +446,12 @@ static int acpi_hibernation_enter(void)
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
}
+static void acpi_hibernation_finish(void)
+{
+ hibernate_nvs_free();
+ acpi_pm_finish();
+}
+
static void acpi_hibernation_leave(void)
{
/*
@@ -432,18 +467,20 @@ static void acpi_hibernation_leave(void)
"cannot resume!\n");
panic("ACPI S4 hardware signature mismatch");
}
+ /* Restore the NVS memory area */
+ hibernate_nvs_restore();
}
static void acpi_pm_enable_gpes(void)
{
- acpi_hw_enable_all_runtime_gpes();
+ acpi_enable_all_runtime_gpes();
}
static struct platform_hibernation_ops acpi_hibernation_ops = {
.begin = acpi_hibernation_begin,
.end = acpi_pm_end,
- .pre_snapshot = acpi_pm_prepare,
- .finish = acpi_pm_finish,
+ .pre_snapshot = acpi_hibernation_pre_snapshot,
+ .finish = acpi_hibernation_finish,
.prepare = acpi_pm_prepare,
.enter = acpi_hibernation_enter,
.leave = acpi_hibernation_leave,
@@ -469,8 +506,22 @@ static int acpi_hibernation_begin_old(void)
error = acpi_sleep_prepare(ACPI_STATE_S4);
+ if (!error) {
+ if (!s4_no_nvs)
+ error = hibernate_nvs_alloc();
+ if (!error)
+ acpi_target_sleep_state = ACPI_STATE_S4;
+ }
+ return error;
+}
+
+static int acpi_hibernation_pre_snapshot_old(void)
+{
+ int error = acpi_pm_disable_gpes();
+
if (!error)
- acpi_target_sleep_state = ACPI_STATE_S4;
+ hibernate_nvs_save();
+
return error;
}
@@ -481,8 +532,8 @@ static int acpi_hibernation_begin_old(void)
static struct platform_hibernation_ops acpi_hibernation_ops_old = {
.begin = acpi_hibernation_begin_old,
.end = acpi_pm_end,
- .pre_snapshot = acpi_pm_disable_gpes,
- .finish = acpi_pm_finish,
+ .pre_snapshot = acpi_hibernation_pre_snapshot_old,
+ .finish = acpi_hibernation_finish,
.prepare = acpi_pm_disable_gpes,
.enter = acpi_hibernation_enter,
.leave = acpi_hibernation_leave,
@@ -622,7 +673,7 @@ static void acpi_power_off_prepare(void)
{
/* Prepare to power off the system */
acpi_sleep_prepare(ACPI_STATE_S5);
- acpi_hw_disable_all_gpes();
+ acpi_disable_all_gpes();
}
static void acpi_power_off(void)
@@ -671,7 +722,7 @@ int __init acpi_sleep_init(void)
sleep_states[ACPI_STATE_S4] = 1;
printk(" S4");
if (!nosigcheck) {
- acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ acpi_get_table(ACPI_SIG_FACS, 1,
(struct acpi_table_header **)&facs);
if (facs)
s4_hardware_signature =
diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep.h
index cfaf8f5b0a14..cfaf8f5b0a14 100644
--- a/drivers/acpi/sleep/sleep.h
+++ b/drivers/acpi/sleep.h
diff --git a/drivers/acpi/sleep/Makefile b/drivers/acpi/sleep/Makefile
deleted file mode 100644
index f1fb888c2d29..000000000000
--- a/drivers/acpi/sleep/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-obj-y := wakeup.o
-obj-y += main.o
-obj-$(CONFIG_ACPI_SLEEP) += proc.o
-
-EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 6e4107f82403..391d0358a592 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -192,65 +192,6 @@ static struct attribute_group interrupt_stats_attr_group = {
};
static struct kobj_attribute *counter_attrs;
-static int count_num_gpes(void)
-{
- int count = 0;
- struct acpi_gpe_xrupt_info *gpe_xrupt_info;
- struct acpi_gpe_block_info *gpe_block;
- acpi_cpu_flags flags;
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
- while (gpe_xrupt_info) {
- gpe_block = gpe_xrupt_info->gpe_block_list_head;
- while (gpe_block) {
- count += gpe_block->register_count *
- ACPI_GPE_REGISTER_WIDTH;
- gpe_block = gpe_block->next;
- }
- gpe_xrupt_info = gpe_xrupt_info->next;
- }
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
-
- return count;
-}
-
-static int get_gpe_device(int index, acpi_handle *handle)
-{
- struct acpi_gpe_xrupt_info *gpe_xrupt_info;
- struct acpi_gpe_block_info *gpe_block;
- acpi_cpu_flags flags;
- struct acpi_namespace_node *node;
-
- flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
-
- gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
- while (gpe_xrupt_info) {
- gpe_block = gpe_xrupt_info->gpe_block_list_head;
- node = gpe_block->node;
- while (gpe_block) {
- index -= gpe_block->register_count *
- ACPI_GPE_REGISTER_WIDTH;
- if (index < 0) {
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- /* return NULL if it's FADT GPE */
- if (node->type != ACPI_TYPE_DEVICE)
- *handle = NULL;
- else
- *handle = node;
- return 0;
- }
- node = gpe_block->node;
- gpe_block = gpe_block->next;
- }
- gpe_xrupt_info = gpe_xrupt_info->next;
- }
- acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
-
- return -ENODEV;
-}
-
static void delete_gpe_attr_array(void)
{
struct event_counter *tmp = all_counters;
@@ -309,7 +250,7 @@ static int get_status(u32 index, acpi_event_status *status, acpi_handle *handle)
goto end;
if (index < num_gpes) {
- result = get_gpe_device(index, handle);
+ result = acpi_get_gpe_device(index, handle);
if (result) {
ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND,
"Invalid GPE 0x%x\n", index));
@@ -436,7 +377,7 @@ void acpi_irq_stats_init(void)
if (all_counters)
return;
- num_gpes = count_num_gpes();
+ num_gpes = acpi_current_gpe_count;
num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA;
all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1),
diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile
deleted file mode 100644
index 7385efa61622..000000000000
--- a/drivers/acpi/tables/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for all Linux ACPI interpreter subdirectories
-#
-
-obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
-
-EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 073ff09218a9..99e6f1f8ea45 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -416,7 +416,8 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
}
/* Passive (optional) */
- if (flag & ACPI_TRIPS_PASSIVE) {
+ if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.flags.valid) ||
+ (flag == ACPI_TRIPS_INIT)) {
valid = tz->trips.passive.flags.valid;
if (psv == -1) {
status = AE_SUPPORT;
@@ -462,8 +463,11 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
memset(&devices, 0, sizeof(struct acpi_handle_list));
status = acpi_evaluate_reference(tz->device->handle, "_PSL",
NULL, &devices);
- if (ACPI_FAILURE(status))
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_WARNING PREFIX
+ "Invalid passive threshold\n");
tz->trips.passive.flags.valid = 0;
+ }
else
tz->trips.passive.flags.valid = 1;
@@ -487,7 +491,8 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
if (act == -1)
break; /* disable all active trip points */
- if (flag & ACPI_TRIPS_ACTIVE) {
+ if ((flag == ACPI_TRIPS_INIT) || ((flag & ACPI_TRIPS_ACTIVE) &&
+ tz->trips.active[i].flags.valid)) {
status = acpi_evaluate_integer(tz->device->handle,
name, NULL, &tmp);
if (ACPI_FAILURE(status)) {
@@ -521,8 +526,11 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
memset(&devices, 0, sizeof(struct acpi_handle_list));
status = acpi_evaluate_reference(tz->device->handle,
name, NULL, &devices);
- if (ACPI_FAILURE(status))
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_WARNING PREFIX
+ "Invalid active%d threshold\n", i);
tz->trips.active[i].flags.valid = 0;
+ }
else
tz->trips.active[i].flags.valid = 1;
diff --git a/drivers/acpi/utilities/Makefile b/drivers/acpi/utilities/Makefile
deleted file mode 100644
index 88eff14c4894..000000000000
--- a/drivers/acpi/utilities/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for all Linux ACPI interpreter subdirectories
-#
-
-obj-y := utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \
- utcopy.o utdelete.o utglobal.o utmath.o utobject.o \
- utstate.o utmutex.o utobject.o utcache.o utresrc.o
-
-EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c
deleted file mode 100644
index 245fa80cf600..000000000000
--- a/drivers/acpi/utilities/utcache.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/******************************************************************************
- *
- * Module Name: utcache - local cache allocation routines
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2008, Intel Corp.
- * 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
- * substantially 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 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 <acpi/acpi.h>
-
-#define _COMPONENT ACPI_UTILITIES
-ACPI_MODULE_NAME("utcache")
-#ifdef ACPI_USE_LOCAL_CACHE
-/*******************************************************************************
- *
- * FUNCTION: acpi_os_create_cache
- *
- * PARAMETERS: cache_name - Ascii name for the cache
- * object_size - Size of each cached object
- * max_depth - Maximum depth of the cache (in objects)
- * return_cache - Where the new cache object is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Create a cache object
- *
- ******************************************************************************/
-acpi_status
-acpi_os_create_cache(char *cache_name,
- u16 object_size,
- u16 max_depth, struct acpi_memory_list ** return_cache)
-{
- struct acpi_memory_list *cache;
-
- ACPI_FUNCTION_ENTRY();
-
- if (!cache_name || !return_cache || (object_size < 16)) {
- return (AE_BAD_PARAMETER);
- }
-
- /* Create the cache object */
-
- cache = acpi_os_allocate(sizeof(struct acpi_memory_list));
- if (!cache) {
- return (AE_NO_MEMORY);
- }
-
- /* Populate the cache object and return it */
-
- ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list));
- cache->link_offset = 8;
- cache->list_name = cache_name;
- cache->object_size = object_size;
- cache->max_depth = max_depth;
-
- *return_cache = cache;
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_os_purge_cache
- *
- * PARAMETERS: Cache - Handle to cache object
- *
- * RETURN: Status
- *
- * DESCRIPTION: Free all objects within the requested cache.
- *
- ******************************************************************************/
-
-acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache)
-{
- char *next;
-
- ACPI_FUNCTION_ENTRY();
-
- if (!cache) {
- return (AE_BAD_PARAMETER);
- }
-
- /* Walk the list of objects in this cache */
-
- while (cache->list_head) {
-
- /* Delete and unlink one cached state object */
-
- next = *(ACPI_CAST_INDIRECT_PTR(char,
- &(((char *)cache->
- list_head)[cache->
- link_offset])));
- ACPI_FREE(cache->list_head);
-
- cache->list_head = next;
- cache->current_depth--;
- }
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_os_delete_cache
- *
- * PARAMETERS: Cache - Handle to cache object
- *
- * RETURN: Status
- *
- * DESCRIPTION: Free all objects within the requested cache and delete the
- * cache object.
- *
- ******************************************************************************/
-
-acpi_status acpi_os_delete_cache(struct acpi_memory_list * cache)
-{
- acpi_status status;
-
- ACPI_FUNCTION_ENTRY();
-
- /* Purge all objects in the cache */
-
- status = acpi_os_purge_cache(cache);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- /* Now we can delete the cache object */
-
- ACPI_FREE(cache);
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_os_release_object
- *
- * PARAMETERS: Cache - Handle to cache object
- * Object - The object to be released
- *
- * RETURN: None
- *
- * DESCRIPTION: Release an object to the specified cache. If cache is full,
- * the object is deleted.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_os_release_object(struct acpi_memory_list * cache, void *object)
-{
- acpi_status status;
-
- ACPI_FUNCTION_ENTRY();
-
- if (!cache || !object) {
- return (AE_BAD_PARAMETER);
- }
-
- /* If cache is full, just free this object */
-
- if (cache->current_depth >= cache->max_depth) {
- ACPI_FREE(object);
- ACPI_MEM_TRACKING(cache->total_freed++);
- }
-
- /* Otherwise put this object back into the cache */
-
- else {
- status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- /* Mark the object as cached */
-
- ACPI_MEMSET(object, 0xCA, cache->object_size);
- ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED);
-
- /* Put the object at the head of the cache list */
-
- *(ACPI_CAST_INDIRECT_PTR(char,
- &(((char *)object)[cache->
- link_offset]))) =
- cache->list_head;
- cache->list_head = object;
- cache->current_depth++;
-
- (void)acpi_ut_release_mutex(ACPI_MTX_CACHES);
- }
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_os_acquire_object
- *
- * PARAMETERS: Cache - Handle to cache object
- *
- * RETURN: the acquired object. NULL on error
- *
- * DESCRIPTION: Get an object from the specified cache. If cache is empty,
- * the object is allocated.
- *
- ******************************************************************************/
-
-void *acpi_os_acquire_object(struct acpi_memory_list *cache)
-{
- acpi_status status;
- void *object;
-
- ACPI_FUNCTION_NAME(os_acquire_object);
-
- if (!cache) {
- return (NULL);
- }
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES);
- if (ACPI_FAILURE(status)) {
- return (NULL);
- }
-
- ACPI_MEM_TRACKING(cache->requests++);
-
- /* Check the cache first */
-
- if (cache->list_head) {
-
- /* There is an object available, use it */
-
- object = cache->list_head;
- cache->list_head = *(ACPI_CAST_INDIRECT_PTR(char,
- &(((char *)
- object)[cache->
- link_offset])));
-
- cache->current_depth--;
-
- ACPI_MEM_TRACKING(cache->hits++);
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Object %p from %s cache\n", object,
- cache->list_name));
-
- status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
- if (ACPI_FAILURE(status)) {
- return (NULL);
- }
-
- /* Clear (zero) the previously used Object */
-
- ACPI_MEMSET(object, 0, cache->object_size);
- } else {
- /* The cache is empty, create a new object */
-
- ACPI_MEM_TRACKING(cache->total_allocated++);
-
-#ifdef ACPI_DBG_TRACK_ALLOCATIONS
- if ((cache->total_allocated - cache->total_freed) >
- cache->max_occupied) {
- cache->max_occupied =
- cache->total_allocated - cache->total_freed;
- }
-#endif
-
- /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
-
- status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
- if (ACPI_FAILURE(status)) {
- return (NULL);
- }
-
- object = ACPI_ALLOCATE_ZEROED(cache->object_size);
- if (!object) {
- return (NULL);
- }
- }
-
- return (object);
-}
-#endif /* ACPI_USE_LOCAL_CACHE */
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index baa441929720..f261737636da 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -36,6 +36,7 @@
#include <linux/backlight.h>
#include <linux/thermal.h>
#include <linux/video_output.h>
+#include <linux/sort.h>
#include <asm/uaccess.h>
#include <acpi/acpi_bus.h>
@@ -481,6 +482,7 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
int status = AE_OK;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
+ int state;
arg0.integer.value = level;
@@ -489,6 +491,10 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
status = acpi_evaluate_object(device->dev->handle, "_BCM",
&args, NULL);
device->brightness->curr = level;
+ for (state = 2; state < device->brightness->count; state++)
+ if (level == device->brightness->levels[state])
+ device->backlight->props.brightness = state - 2;
+
return status;
}
@@ -626,6 +632,16 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
}
/*
+ * Simple comparison function used to sort backlight levels.
+ */
+
+static int
+acpi_video_cmp_level(const void *a, const void *b)
+{
+ return *(int *)a - *(int *)b;
+}
+
+/*
* Arg:
* device : video output device (LCD, CRT, ..)
*
@@ -676,6 +692,10 @@ acpi_video_init_brightness(struct acpi_video_device *device)
count++;
}
+ /* don't sort the first two brightness levels */
+ sort(&br->levels[2], count - 2, sizeof(br->levels[2]),
+ acpi_video_cmp_level, NULL);
+
if (count < 2)
goto out_free_levels;
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index f022eb6f5637..50e3d2dbf3af 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -234,7 +234,7 @@ EXPORT_SYMBOL(acpi_video_display_switch_support);
* To force that backlight or display output switching is processed by vendor
* specific acpi drivers or video.ko driver.
*/
-int __init acpi_backlight(char *str)
+static int __init acpi_backlight(char *str)
{
if (str == NULL || *str == '\0')
return 1;
@@ -250,7 +250,7 @@ int __init acpi_backlight(char *str)
}
__setup("acpi_backlight=", acpi_backlight);
-int __init acpi_display_output(char *str)
+static int __init acpi_display_output(char *str)
{
if (str == NULL || *str == '\0')
return 1;
diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/wakeup.c
index dea4c23df764..2d34806d45dd 100644
--- a/drivers/acpi/sleep/wakeup.c
+++ b/drivers/acpi/wakeup.c
@@ -8,7 +8,6 @@
#include <acpi/acpi_drivers.h>
#include <linux/kernel.h>
#include <linux/types.h>
-#include <acpi/acevents.h>
#include "sleep.h"
#define _COMPONENT ACPI_SYSTEM_COMPONENT
@@ -28,8 +27,6 @@ void acpi_enable_wakeup_device_prep(u8 sleep_state)
{
struct list_head *node, *next;
- ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_prep");
-
spin_lock(&acpi_device_lock);
list_for_each_safe(node, next, &acpi_wakeup_device_list) {
struct acpi_device *dev = container_of(node,
@@ -61,7 +58,6 @@ void acpi_enable_wakeup_device(u8 sleep_state)
* Caution: this routine must be invoked when interrupt is disabled
* Refer ACPI2.0: P212
*/
- ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device");
spin_lock(&acpi_device_lock);
list_for_each_safe(node, next, &acpi_wakeup_device_list) {
struct acpi_device *dev =
@@ -103,8 +99,6 @@ void acpi_disable_wakeup_device(u8 sleep_state)
{
struct list_head *node, *next;
- ACPI_FUNCTION_TRACE("acpi_disable_wakeup_device");
-
spin_lock(&acpi_device_lock);
list_for_each_safe(node, next, &acpi_wakeup_device_list) {
struct acpi_device *dev =
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 6b94fb7be5f2..00c46e0b40e4 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -12,9 +12,10 @@
#include <linux/device.h>
#include <linux/string.h>
#include <linux/slab.h>
+#include <linux/io.h>
#include <linux/amba/bus.h>
-#include <asm/io.h>
+#include <asm/irq.h>
#include <asm/sizes.h>
#define to_amba_device(d) container_of(d, struct amba_device, dev)
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 1a7be96d627b..503a908afc80 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -698,6 +698,15 @@ config PATA_IXP4XX_CF
If unsure, say N.
+config PATA_OCTEON_CF
+ tristate "OCTEON Boot Bus Compact Flash support"
+ depends on CPU_CAVIUM_OCTEON
+ help
+ This option enables a polled compact flash driver for use with
+ compact flash cards attached to the OCTEON boot bus.
+
+ If unsure, say N.
+
config PATA_SCC
tristate "Toshiba's Cell Reference Set IDE support"
depends on PCI && PPC_CELLEB
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 674965fa326d..7f1ecf99528c 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
obj-$(CONFIG_PATA_SCC) += pata_scc.o
obj-$(CONFIG_PATA_SCH) += pata_sch.o
obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o
+obj-$(CONFIG_PATA_OCTEON_CF) += pata_octeon_cf.o
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 656448c7fef9..96039671e3b9 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -105,7 +105,7 @@ enum {
board_ahci_ign_iferr = 2,
board_ahci_sb600 = 3,
board_ahci_mv = 4,
- board_ahci_sb700 = 5,
+ board_ahci_sb700 = 5, /* for SB700 and SB800 */
board_ahci_mcp65 = 6,
board_ahci_nopmp = 7,
@@ -439,7 +439,7 @@ static const struct ata_port_info ahci_port_info[] = {
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_ops,
},
- /* board_ahci_sb700 */
+ /* board_ahci_sb700, for SB700 and SB800 */
{
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL),
.flags = AHCI_FLAG_COMMON,
@@ -2446,6 +2446,8 @@ static void ahci_print_info(struct ata_host *host)
speed_s = "1.5";
else if (speed == 2)
speed_s = "3";
+ else if (speed == 3)
+ speed_s = "6";
else
speed_s = "?";
@@ -2610,6 +2612,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
(pdev->revision == 0xa1 || pdev->revision == 0xa2))
hpriv->flags |= AHCI_HFLAG_NO_MSI;
+ /* SB800 does NOT need the workaround to ignore SERR_INTERNAL */
+ if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
+ hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
+
if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
pci_intx(pdev, 1);
@@ -2654,6 +2660,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
host->iomap = pcim_iomap_table(pdev);
host->private_data = hpriv;
+ if (!(hpriv->cap & HOST_CAP_SSS))
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+
if (pi.flags & ATA_FLAG_EM)
ahci_reset_em(host);
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 5fdf1678d0cc..887d8f46a287 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -154,11 +154,13 @@ struct piix_map_db {
struct piix_host_priv {
const int *map;
+ u32 saved_iocfg;
void __iomem *sidpr;
};
static int piix_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent);
+static void piix_remove_one(struct pci_dev *pdev);
static int piix_pata_prereset(struct ata_link *link, unsigned long deadline);
static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev);
static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev);
@@ -296,7 +298,7 @@ static struct pci_driver piix_pci_driver = {
.name = DRV_NAME,
.id_table = piix_pci_tbl,
.probe = piix_init_one,
- .remove = ata_pci_remove_one,
+ .remove = piix_remove_one,
#ifdef CONFIG_PM
.suspend = piix_pci_device_suspend,
.resume = piix_pci_device_resume,
@@ -308,7 +310,7 @@ static struct scsi_host_template piix_sht = {
};
static struct ata_port_operations piix_pata_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma32_port_ops,
.cable_detect = ata_cable_40wire,
.set_piomode = piix_set_piomode,
.set_dmamode = piix_set_dmamode,
@@ -610,8 +612,9 @@ static const struct ich_laptop ich_laptop[] = {
static int ich_pata_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct piix_host_priv *hpriv = ap->host->private_data;
const struct ich_laptop *lap = &ich_laptop[0];
- u8 tmp, mask;
+ u8 mask;
/* Check for specials - Acer Aspire 5602WLMi */
while (lap->device) {
@@ -625,8 +628,7 @@ static int ich_pata_cable_detect(struct ata_port *ap)
/* check BIOS cable detect results */
mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
- pci_read_config_byte(pdev, PIIX_IOCFG, &tmp);
- if ((tmp & mask) == 0)
+ if ((hpriv->saved_iocfg & mask) == 0)
return ATA_CBL_PATA40;
return ATA_CBL_PATA80;
}
@@ -1350,7 +1352,7 @@ static int __devinit piix_init_sidpr(struct ata_host *host)
return 0;
}
-static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
+static void piix_iocfg_bit18_quirk(struct ata_host *host)
{
static const struct dmi_system_id sysids[] = {
{
@@ -1367,7 +1369,8 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
{ } /* terminate list */
};
- u32 iocfg;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ struct piix_host_priv *hpriv = host->private_data;
if (!dmi_check_system(sysids))
return;
@@ -1376,12 +1379,11 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
* seem to use it to disable a channel. Clear the bit on the
* affected systems.
*/
- pci_read_config_dword(pdev, PIIX_IOCFG, &iocfg);
- if (iocfg & (1 << 18)) {
+ if (hpriv->saved_iocfg & (1 << 18)) {
dev_printk(KERN_INFO, &pdev->dev,
"applying IOCFG bit18 quirk\n");
- iocfg &= ~(1 << 18);
- pci_write_config_dword(pdev, PIIX_IOCFG, iocfg);
+ pci_write_config_dword(pdev, PIIX_IOCFG,
+ hpriv->saved_iocfg & ~(1 << 18));
}
}
@@ -1430,6 +1432,17 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
if (rc)
return rc;
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
+
+ /* Save IOCFG, this will be used for cable detection, quirk
+ * detection and restoration on detach. This is necessary
+ * because some ACPI implementations mess up cable related
+ * bits on _STM. Reported on kernel bz#11879.
+ */
+ pci_read_config_dword(pdev, PIIX_IOCFG, &hpriv->saved_iocfg);
+
/* ICH6R may be driven by either ata_piix or ahci driver
* regardless of BIOS configuration. Make sure AHCI mode is
* off.
@@ -1441,10 +1454,6 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
}
/* SATA map init can change port_info, do it before prepping host */
- hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv)
- return -ENOMEM;
-
if (port_flags & ATA_FLAG_SATA)
hpriv->map = piix_init_sata_map(pdev, port_info,
piix_map_db_table[ent->driver_data]);
@@ -1463,7 +1472,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
}
/* apply IOCFG bit18 quirk */
- piix_iocfg_bit18_quirk(pdev);
+ piix_iocfg_bit18_quirk(host);
/* On ICH5, some BIOSen disable the interrupt using the
* PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
@@ -1488,6 +1497,16 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht);
}
+static void piix_remove_one(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct piix_host_priv *hpriv = host->private_data;
+
+ pci_write_config_dword(pdev, PIIX_IOCFG, hpriv->saved_iocfg);
+
+ ata_pci_remove_one(pdev);
+}
+
static int __init piix_init(void)
{
int rc;
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index ef02e488d468..6273d98d00eb 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -19,12 +19,6 @@
#include "libata.h"
#include <acpi/acpi_bus.h>
-#include <acpi/acnames.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acparser.h>
-#include <acpi/acexcep.h>
-#include <acpi/acmacros.h>
-#include <acpi/actypes.h>
enum {
ATA_ACPI_FILTER_SETXFER = 1 << 0,
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index fecca4223f8e..88c242856dae 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -56,6 +56,7 @@
#include <linux/workqueue.h>
#include <linux/scatterlist.h>
#include <linux/io.h>
+#include <linux/async.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
@@ -1006,6 +1007,7 @@ static const char *sata_spd_string(unsigned int spd)
static const char * const spd_str[] = {
"1.5 Gbps",
"3.0 Gbps",
+ "6.0 Gbps",
};
if (spd == 0 || (spd - 1) >= ARRAY_SIZE(spd_str))
@@ -1999,6 +2001,10 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
as the caller should know this */
if (adev->link->ap->flags & ATA_FLAG_NO_IORDY)
return 0;
+ /* CF spec. r4.1 Table 22 says no iordy on PIO5 and PIO6. */
+ if (ata_id_is_cfa(adev->id)
+ && (adev->pio_mode == XFER_PIO_5 || adev->pio_mode == XFER_PIO_6))
+ return 0;
/* PIO3 and higher it is mandatory */
if (adev->pio_mode > XFER_PIO_2)
return 1;
@@ -3023,33 +3029,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_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_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_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 },
-
-/* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, */
- { 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 },
+/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 0, 960, 0 }, */
+ { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 0, 600, 0 },
+ { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 0, 383, 0 },
+ { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 0, 240, 0 },
+ { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 0, 180, 0 },
+ { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 0, 120, 0 },
+ { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 0, 100, 0 },
+ { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 0, 80, 0 },
+
+ { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 50, 960, 0 },
+ { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 30, 480, 0 },
+ { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 20, 240, 0 },
+
+ { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 20, 480, 0 },
+ { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 5, 150, 0 },
+ { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 5, 120, 0 },
+ { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 5, 100, 0 },
+ { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 5, 80, 0 },
+
+/* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 0, 150 }, */
+ { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 0, 120 },
+ { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 0, 80 },
+ { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 0, 60 },
+ { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 0, 45 },
+ { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 0, 30 },
+ { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 0, 20 },
+ { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 0, 15 },
{ 0xFF }
};
@@ -3059,14 +3065,15 @@ static const struct ata_timing ata_timing[] = {
static void ata_timing_quantize(const struct ata_timing *t, struct ata_timing *q, int T, int UT)
{
- q->setup = EZ(t->setup * 1000, T);
- q->act8b = EZ(t->act8b * 1000, T);
- q->rec8b = EZ(t->rec8b * 1000, T);
- q->cyc8b = EZ(t->cyc8b * 1000, T);
- q->active = EZ(t->active * 1000, T);
- q->recover = EZ(t->recover * 1000, T);
- q->cycle = EZ(t->cycle * 1000, T);
- q->udma = EZ(t->udma * 1000, UT);
+ q->setup = EZ(t->setup * 1000, T);
+ q->act8b = EZ(t->act8b * 1000, T);
+ q->rec8b = EZ(t->rec8b * 1000, T);
+ q->cyc8b = EZ(t->cyc8b * 1000, T);
+ q->active = EZ(t->active * 1000, T);
+ q->recover = EZ(t->recover * 1000, T);
+ q->dmack_hold = EZ(t->dmack_hold * 1000, T);
+ q->cycle = EZ(t->cycle * 1000, T);
+ q->udma = EZ(t->udma * 1000, UT);
}
void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
@@ -3078,6 +3085,7 @@ void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b,
if (what & ATA_TIMING_CYC8B ) m->cyc8b = max(a->cyc8b, b->cyc8b);
if (what & ATA_TIMING_ACTIVE ) m->active = max(a->active, b->active);
if (what & ATA_TIMING_RECOVER) m->recover = max(a->recover, b->recover);
+ if (what & ATA_TIMING_DMACK_HOLD) m->dmack_hold = max(a->dmack_hold, b->dmack_hold);
if (what & ATA_TIMING_CYCLE ) m->cycle = max(a->cycle, b->cycle);
if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma);
}
@@ -4550,7 +4558,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
struct scatterlist *sg = qc->sg;
int dir = qc->dma_dir;
- WARN_ON(sg == NULL);
+ WARN_ON_ONCE(sg == NULL);
VPRINTK("unmapping %u sg elements\n", qc->n_elem);
@@ -4770,7 +4778,7 @@ void ata_qc_free(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
unsigned int tag;
- WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
+ WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
qc->flags = 0;
tag = qc->tag;
@@ -4785,8 +4793,8 @@ void __ata_qc_complete(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct ata_link *link = qc->dev->link;
- WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
- WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
+ WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
+ WARN_ON_ONCE(!(qc->flags & ATA_QCFLAG_ACTIVE));
if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
ata_sg_clean(qc);
@@ -4872,7 +4880,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
struct ata_device *dev = qc->dev;
struct ata_eh_info *ehi = &dev->link->eh_info;
- WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
+ WARN_ON_ONCE(ap->pflags & ATA_PFLAG_FROZEN);
if (unlikely(qc->err_mask))
qc->flags |= ATA_QCFLAG_FAILED;
@@ -4994,16 +5002,16 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
* check is skipped for old EH because it reuses active qc to
* request ATAPI sense.
*/
- WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag));
+ WARN_ON_ONCE(ap->ops->error_handler && ata_tag_valid(link->active_tag));
if (ata_is_ncq(prot)) {
- WARN_ON(link->sactive & (1 << qc->tag));
+ WARN_ON_ONCE(link->sactive & (1 << qc->tag));
if (!link->sactive)
ap->nr_active_links++;
link->sactive |= 1 << qc->tag;
} else {
- WARN_ON(link->sactive);
+ WARN_ON_ONCE(link->sactive);
ap->nr_active_links++;
link->active_tag = qc->tag;
@@ -5909,6 +5917,65 @@ void ata_host_init(struct ata_host *host, struct device *dev,
host->ops = ops;
}
+
+static void async_port_probe(void *data, async_cookie_t cookie)
+{
+ int rc;
+ struct ata_port *ap = data;
+
+ /*
+ * If we're not allowed to scan this host in parallel,
+ * we need to wait until all previous scans have completed
+ * before going further.
+ * Jeff Garzik says this is only within a controller, so we
+ * don't need to wait for port 0, only for later ports.
+ */
+ if (!(ap->host->flags & ATA_HOST_PARALLEL_SCAN) && ap->port_no != 0)
+ async_synchronize_cookie(cookie);
+
+ /* probe */
+ if (ap->ops->error_handler) {
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ unsigned long flags;
+
+ ata_port_probe(ap);
+
+ /* kick EH for boot probing */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ehi->probe_mask |= ATA_ALL_DEVICES;
+ ehi->action |= ATA_EH_RESET | ATA_EH_LPM;
+ ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
+
+ ap->pflags &= ~ATA_PFLAG_INITIALIZING;
+ ap->pflags |= ATA_PFLAG_LOADING;
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* wait for EH to finish */
+ ata_port_wait_eh(ap);
+ } else {
+ DPRINTK("ata%u: bus probe begin\n", ap->print_id);
+ rc = ata_bus_probe(ap);
+ DPRINTK("ata%u: bus probe end\n", ap->print_id);
+
+ if (rc) {
+ /* FIXME: do something useful here?
+ * Current libata behavior will
+ * tear down everything when
+ * the module is removed
+ * or the h/w is unplugged.
+ */
+ }
+ }
+
+ /* in order to keep device order, we need to synchronize at this point */
+ async_synchronize_cookie(cookie);
+
+ ata_scsi_scan_host(ap, 1);
+
+}
/**
* ata_host_register - register initialized ATA host
* @host: ATA host to register
@@ -5988,52 +6055,9 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
DPRINTK("probe begin\n");
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
-
- /* probe */
- if (ap->ops->error_handler) {
- struct ata_eh_info *ehi = &ap->link.eh_info;
- unsigned long flags;
-
- ata_port_probe(ap);
-
- /* kick EH for boot probing */
- spin_lock_irqsave(ap->lock, flags);
-
- ehi->probe_mask |= ATA_ALL_DEVICES;
- ehi->action |= ATA_EH_RESET | ATA_EH_LPM;
- ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
-
- ap->pflags &= ~ATA_PFLAG_INITIALIZING;
- ap->pflags |= ATA_PFLAG_LOADING;
- ata_port_schedule_eh(ap);
-
- spin_unlock_irqrestore(ap->lock, flags);
-
- /* wait for EH to finish */
- ata_port_wait_eh(ap);
- } else {
- DPRINTK("ata%u: bus probe begin\n", ap->print_id);
- rc = ata_bus_probe(ap);
- DPRINTK("ata%u: bus probe end\n", ap->print_id);
-
- if (rc) {
- /* FIXME: do something useful here?
- * Current libata behavior will
- * tear down everything when
- * the module is removed
- * or the h/w is unplugged.
- */
- }
- }
- }
-
- /* probes are done, now scan each port's disk(s) */
- DPRINTK("host probe begin\n");
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap = host->ports[i];
-
- ata_scsi_scan_host(ap, 1);
+ async_schedule(async_port_probe, ap);
}
+ DPRINTK("probe end\n");
return 0;
}
@@ -6616,7 +6640,6 @@ EXPORT_SYMBOL_GPL(ata_dev_pair);
EXPORT_SYMBOL_GPL(ata_port_disable);
EXPORT_SYMBOL_GPL(ata_ratelimit);
EXPORT_SYMBOL_GPL(ata_wait_register);
-EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
EXPORT_SYMBOL_GPL(ata_scsi_slave_destroy);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 9e92107691f2..a1a6e6298c33 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -423,9 +423,9 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
* RETURNS:
* Zero on success, negative errno on error.
*/
-static int ata_get_identity(struct scsi_device *sdev, void __user *arg)
+static int ata_get_identity(struct ata_port *ap, struct scsi_device *sdev,
+ void __user *arg)
{
- struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
u16 __user *dst = arg;
char buf[40];
@@ -645,7 +645,8 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg)
return rc;
}
-int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
+int ata_sas_scsi_ioctl(struct ata_port *ap, struct scsi_device *scsidev,
+ int cmd, void __user *arg)
{
int val = -EINVAL, rc = -EINVAL;
@@ -663,7 +664,7 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
return 0;
case HDIO_GET_IDENTITY:
- return ata_get_identity(scsidev, arg);
+ return ata_get_identity(ap, scsidev, arg);
case HDIO_DRIVE_CMD:
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
@@ -682,6 +683,14 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
return rc;
}
+EXPORT_SYMBOL_GPL(ata_sas_scsi_ioctl);
+
+int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
+{
+ return ata_sas_scsi_ioctl(ata_shost_to_port(scsidev->host),
+ scsidev, cmd, arg);
+}
+EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
/**
* ata_scsi_qc_new - acquire new ata_queued_cmd reference
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 9033d164c4ec..5a4aad123c42 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -66,6 +66,7 @@ const struct ata_port_operations ata_sff_port_ops = {
.port_start = ata_sff_port_start,
};
+EXPORT_SYMBOL_GPL(ata_sff_port_ops);
const struct ata_port_operations ata_bmdma_port_ops = {
.inherits = &ata_sff_port_ops,
@@ -77,6 +78,14 @@ const struct ata_port_operations ata_bmdma_port_ops = {
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
};
+EXPORT_SYMBOL_GPL(ata_bmdma_port_ops);
+
+const struct ata_port_operations ata_bmdma32_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+
+ .sff_data_xfer = ata_sff_data_xfer32,
+};
+EXPORT_SYMBOL_GPL(ata_bmdma32_port_ops);
/**
* ata_fill_sg - Fill PCI IDE PRD table
@@ -166,8 +175,9 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc)
blen = len & 0xffff;
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 */
+ /* Some PATA chipsets like the CS5530 can't
+ cope with 0x0000 meaning 64K as the spec
+ says */
ap->prd[pi].flags_len = cpu_to_le32(0x8000);
blen = 0x8000;
ap->prd[++pi].addr = cpu_to_le32(addr + 0x8000);
@@ -200,6 +210,7 @@ void ata_sff_qc_prep(struct ata_queued_cmd *qc)
ata_fill_sg(qc);
}
+EXPORT_SYMBOL_GPL(ata_sff_qc_prep);
/**
* ata_sff_dumb_qc_prep - Prepare taskfile for submission
@@ -217,6 +228,7 @@ void ata_sff_dumb_qc_prep(struct ata_queued_cmd *qc)
ata_fill_sg_dumb(qc);
}
+EXPORT_SYMBOL_GPL(ata_sff_dumb_qc_prep);
/**
* ata_sff_check_status - Read device status reg & clear interrupt
@@ -233,6 +245,7 @@ u8 ata_sff_check_status(struct ata_port *ap)
{
return ioread8(ap->ioaddr.status_addr);
}
+EXPORT_SYMBOL_GPL(ata_sff_check_status);
/**
* ata_sff_altstatus - Read device alternate status reg
@@ -275,7 +288,7 @@ static u8 ata_sff_irq_status(struct ata_port *ap)
status = ata_sff_altstatus(ap);
/* Not us: We are busy */
if (status & ATA_BUSY)
- return status;
+ return status;
}
/* Clear INTRQ latch */
status = ap->ops->sff_check_status(ap);
@@ -319,6 +332,7 @@ void ata_sff_pause(struct ata_port *ap)
ata_sff_sync(ap);
ndelay(400);
}
+EXPORT_SYMBOL_GPL(ata_sff_pause);
/**
* ata_sff_dma_pause - Pause before commencing DMA
@@ -327,7 +341,7 @@ void ata_sff_pause(struct ata_port *ap)
* Perform I/O fencing and ensure sufficient cycle delays occur
* for the HDMA1:0 transition
*/
-
+
void ata_sff_dma_pause(struct ata_port *ap)
{
if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) {
@@ -341,6 +355,7 @@ void ata_sff_dma_pause(struct ata_port *ap)
corruption. */
BUG();
}
+EXPORT_SYMBOL_GPL(ata_sff_dma_pause);
/**
* ata_sff_busy_sleep - sleep until BSY clears, or timeout
@@ -396,6 +411,7 @@ int ata_sff_busy_sleep(struct ata_port *ap,
return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_busy_sleep);
static int ata_sff_check_ready(struct ata_link *link)
{
@@ -422,6 +438,7 @@ int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline)
{
return ata_wait_ready(link, deadline, ata_sff_check_ready);
}
+EXPORT_SYMBOL_GPL(ata_sff_wait_ready);
/**
* ata_sff_dev_select - Select device 0/1 on ATA bus
@@ -449,6 +466,7 @@ void ata_sff_dev_select(struct ata_port *ap, unsigned int device)
iowrite8(tmp, ap->ioaddr.device_addr);
ata_sff_pause(ap); /* needed; also flushes, for mmio */
}
+EXPORT_SYMBOL_GPL(ata_sff_dev_select);
/**
* ata_dev_select - Select device 0/1 on ATA bus
@@ -513,6 +531,7 @@ u8 ata_sff_irq_on(struct ata_port *ap)
return tmp;
}
+EXPORT_SYMBOL_GPL(ata_sff_irq_on);
/**
* ata_sff_irq_clear - Clear PCI IDE BMDMA interrupt.
@@ -534,6 +553,7 @@ void ata_sff_irq_clear(struct ata_port *ap)
iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS);
}
+EXPORT_SYMBOL_GPL(ata_sff_irq_clear);
/**
* ata_sff_tf_load - send taskfile registers to host controller
@@ -558,7 +578,7 @@ void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
}
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
- WARN_ON(!ioaddr->ctl_addr);
+ WARN_ON_ONCE(!ioaddr->ctl_addr);
iowrite8(tf->hob_feature, ioaddr->feature_addr);
iowrite8(tf->hob_nsect, ioaddr->nsect_addr);
iowrite8(tf->hob_lbal, ioaddr->lbal_addr);
@@ -593,6 +613,7 @@ void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
ata_wait_idle(ap);
}
+EXPORT_SYMBOL_GPL(ata_sff_tf_load);
/**
* ata_sff_tf_read - input device's ATA taskfile shadow registers
@@ -630,9 +651,10 @@ void ata_sff_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
iowrite8(tf->ctl, ioaddr->ctl_addr);
ap->last_ctl = tf->ctl;
} else
- WARN_ON(1);
+ WARN_ON_ONCE(1);
}
}
+EXPORT_SYMBOL_GPL(ata_sff_tf_read);
/**
* ata_sff_exec_command - issue ATA command to host controller
@@ -652,6 +674,7 @@ void ata_sff_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
iowrite8(tf->command, ap->ioaddr.command_addr);
ata_sff_pause(ap);
}
+EXPORT_SYMBOL_GPL(ata_sff_exec_command);
/**
* ata_tf_to_host - issue ATA taskfile to host controller
@@ -717,6 +740,53 @@ unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf,
return words << 1;
}
+EXPORT_SYMBOL_GPL(ata_sff_data_xfer);
+
+/**
+ * ata_sff_data_xfer32 - Transfer data by PIO
+ * @dev: device to target
+ * @buf: data buffer
+ * @buflen: buffer length
+ * @rw: read/write
+ *
+ * Transfer data from/to the device data register by PIO using 32bit
+ * I/O operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ *
+ * RETURNS:
+ * Bytes consumed.
+ */
+
+unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf,
+ unsigned int buflen, int rw)
+{
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned int words = buflen >> 2;
+ int slop = buflen & 3;
+
+ /* Transfer multiple of 4 bytes */
+ if (rw == READ)
+ ioread32_rep(data_addr, buf, words);
+ else
+ iowrite32_rep(data_addr, buf, words);
+
+ if (unlikely(slop)) {
+ __le32 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);
+ }
+ words++;
+ }
+ return words << 2;
+}
+EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
/**
* ata_sff_data_xfer_noirq - Transfer data by PIO
@@ -746,6 +816,7 @@ unsigned int ata_sff_data_xfer_noirq(struct ata_device *dev, unsigned char *buf,
return consumed;
}
+EXPORT_SYMBOL_GPL(ata_sff_data_xfer_noirq);
/**
* ata_pio_sector - Transfer a sector of data.
@@ -820,7 +891,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
/* READ/WRITE MULTIPLE */
unsigned int nsect;
- WARN_ON(qc->dev->multi_count == 0);
+ WARN_ON_ONCE(qc->dev->multi_count == 0);
nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size,
qc->dev->multi_count);
@@ -847,7 +918,7 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
{
/* send SCSI cdb */
DPRINTK("send cdb\n");
- WARN_ON(qc->dev->cdb_len < 12);
+ WARN_ON_ONCE(qc->dev->cdb_len < 12);
ap->ops->sff_data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1);
ata_sff_sync(ap);
@@ -922,13 +993,15 @@ next_sg:
buf = kmap_atomic(page, KM_IRQ0);
/* do the actual data transfer */
- consumed = ap->ops->sff_data_xfer(dev, buf + offset, count, rw);
+ consumed = ap->ops->sff_data_xfer(dev, buf + offset,
+ count, rw);
kunmap_atomic(buf, KM_IRQ0);
local_irq_restore(flags);
} else {
buf = page_address(page);
- consumed = ap->ops->sff_data_xfer(dev, buf + offset, count, rw);
+ consumed = ap->ops->sff_data_xfer(dev, buf + offset,
+ count, rw);
}
bytes -= min(bytes, consumed);
@@ -940,9 +1013,12 @@ next_sg:
qc->cursg_ofs = 0;
}
- /* consumed can be larger than count only for the last transfer */
- WARN_ON(qc->cursg && count != consumed);
-
+ /*
+ * There used to be a WARN_ON_ONCE(qc->cursg && count != consumed);
+ * Unfortunately __atapi_pio_bytes doesn't know enough to do the WARN
+ * check correctly as it doesn't know if it is the last request being
+ * made. Somebody should implement a proper sanity check.
+ */
if (bytes)
goto next_sg;
return 0;
@@ -1013,18 +1089,19 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc)
* RETURNS:
* 1 if ok in workqueue, 0 otherwise.
*/
-static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc)
+static inline int ata_hsm_ok_in_wq(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
{
if (qc->tf.flags & ATA_TFLAG_POLLING)
return 1;
if (ap->hsm_task_state == HSM_ST_FIRST) {
if (qc->tf.protocol == ATA_PROT_PIO &&
- (qc->tf.flags & ATA_TFLAG_WRITE))
+ (qc->tf.flags & ATA_TFLAG_WRITE))
return 1;
if (ata_is_atapi(qc->tf.protocol) &&
- !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
return 1;
}
@@ -1098,13 +1175,13 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
unsigned long flags = 0;
int poll_next;
- WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
+ WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
/* Make sure ata_sff_qc_issue() does not throw things
* like DMA polling into the workqueue. Notice that
* in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING).
*/
- WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc));
+ WARN_ON_ONCE(in_wq != ata_hsm_ok_in_wq(ap, qc));
fsm_start:
DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n",
@@ -1313,7 +1390,7 @@ fsm_start:
DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n",
ap->print_id, qc->dev->devno, status);
- WARN_ON(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM));
+ WARN_ON_ONCE(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM));
ap->hsm_task_state = HSM_ST_IDLE;
@@ -1338,6 +1415,7 @@ fsm_start:
return poll_next;
}
+EXPORT_SYMBOL_GPL(ata_sff_hsm_move);
void ata_pio_task(struct work_struct *work)
{
@@ -1348,7 +1426,7 @@ void ata_pio_task(struct work_struct *work)
int poll_next;
fsm_start:
- WARN_ON(ap->hsm_task_state == HSM_ST_IDLE);
+ WARN_ON_ONCE(ap->hsm_task_state == HSM_ST_IDLE);
/*
* This is purely heuristic. This is a fast path.
@@ -1437,7 +1515,7 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc)
break;
case ATA_PROT_DMA:
- WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
+ WARN_ON_ONCE(qc->tf.flags & ATA_TFLAG_POLLING);
ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
@@ -1489,7 +1567,7 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc)
break;
case ATAPI_PROT_DMA:
- WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
+ WARN_ON_ONCE(qc->tf.flags & ATA_TFLAG_POLLING);
ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */
ap->ops->bmdma_setup(qc); /* set up bmdma */
@@ -1501,12 +1579,13 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc)
break;
default:
- WARN_ON(1);
+ WARN_ON_ONCE(1);
return AC_ERR_SYSTEM;
}
return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_qc_issue);
/**
* ata_sff_qc_fill_rtf - fill result TF using ->sff_tf_read
@@ -1526,6 +1605,7 @@ bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc)
qc->ap->ops->sff_tf_read(qc->ap, &qc->result_tf);
return true;
}
+EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf);
/**
* ata_sff_host_intr - Handle host interrupt for given (port, task)
@@ -1623,6 +1703,7 @@ idle_irq:
#endif
return 0; /* irq not handled */
}
+EXPORT_SYMBOL_GPL(ata_sff_host_intr);
/**
* ata_sff_interrupt - Default ATA host interrupt handler
@@ -1667,6 +1748,7 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
return IRQ_RETVAL(handled);
}
+EXPORT_SYMBOL_GPL(ata_sff_interrupt);
/**
* ata_sff_freeze - Freeze SFF controller port
@@ -1695,6 +1777,7 @@ void ata_sff_freeze(struct ata_port *ap)
ap->ops->sff_irq_clear(ap);
}
+EXPORT_SYMBOL_GPL(ata_sff_freeze);
/**
* ata_sff_thaw - Thaw SFF controller port
@@ -1712,6 +1795,7 @@ void ata_sff_thaw(struct ata_port *ap)
ap->ops->sff_irq_clear(ap);
ap->ops->sff_irq_on(ap);
}
+EXPORT_SYMBOL_GPL(ata_sff_thaw);
/**
* ata_sff_prereset - prepare SFF link for reset
@@ -1753,6 +1837,7 @@ int ata_sff_prereset(struct ata_link *link, unsigned long deadline)
return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_prereset);
/**
* ata_devchk - PATA device presence detection
@@ -1865,6 +1950,7 @@ unsigned int ata_sff_dev_classify(struct ata_device *dev, int present,
return class;
}
+EXPORT_SYMBOL_GPL(ata_sff_dev_classify);
/**
* ata_sff_wait_after_reset - wait for devices to become ready after reset
@@ -1941,6 +2027,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask,
return ret;
}
+EXPORT_SYMBOL_GPL(ata_sff_wait_after_reset);
static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
unsigned long deadline)
@@ -2013,6 +2100,7 @@ int ata_sff_softreset(struct ata_link *link, unsigned int *classes,
DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_softreset);
/**
* sata_sff_hardreset - reset host port via SATA phy reset
@@ -2045,6 +2133,7 @@ int sata_sff_hardreset(struct ata_link *link, unsigned int *class,
DPRINTK("EXIT, class=%u\n", *class);
return rc;
}
+EXPORT_SYMBOL_GPL(sata_sff_hardreset);
/**
* ata_sff_postreset - SFF postreset callback
@@ -2080,6 +2169,7 @@ void ata_sff_postreset(struct ata_link *link, unsigned int *classes)
if (ap->ioaddr.ctl_addr)
iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
}
+EXPORT_SYMBOL_GPL(ata_sff_postreset);
/**
* ata_sff_error_handler - Stock error handler for BMDMA controller
@@ -2152,6 +2242,7 @@ void ata_sff_error_handler(struct ata_port *ap)
ata_do_eh(ap, ap->ops->prereset, softreset, hardreset,
ap->ops->postreset);
}
+EXPORT_SYMBOL_GPL(ata_sff_error_handler);
/**
* ata_sff_post_internal_cmd - Stock post_internal_cmd for SFF controller
@@ -2174,6 +2265,7 @@ void ata_sff_post_internal_cmd(struct ata_queued_cmd *qc)
spin_unlock_irqrestore(ap->lock, flags);
}
+EXPORT_SYMBOL_GPL(ata_sff_post_internal_cmd);
/**
* ata_sff_port_start - Set port up for dma.
@@ -2194,6 +2286,7 @@ int ata_sff_port_start(struct ata_port *ap)
return ata_port_start(ap);
return 0;
}
+EXPORT_SYMBOL_GPL(ata_sff_port_start);
/**
* ata_sff_std_ports - initialize ioaddr with standard port offsets.
@@ -2219,6 +2312,7 @@ void ata_sff_std_ports(struct ata_ioports *ioaddr)
ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS;
ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
}
+EXPORT_SYMBOL_GPL(ata_sff_std_ports);
unsigned long ata_bmdma_mode_filter(struct ata_device *adev,
unsigned long xfer_mask)
@@ -2230,6 +2324,7 @@ unsigned long ata_bmdma_mode_filter(struct ata_device *adev,
xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
return xfer_mask;
}
+EXPORT_SYMBOL_GPL(ata_bmdma_mode_filter);
/**
* ata_bmdma_setup - Set up PCI IDE BMDMA transaction
@@ -2258,6 +2353,7 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc)
/* issue r/w command */
ap->ops->sff_exec_command(ap, &qc->tf);
}
+EXPORT_SYMBOL_GPL(ata_bmdma_setup);
/**
* ata_bmdma_start - Start a PCI IDE BMDMA transaction
@@ -2290,6 +2386,7 @@ void ata_bmdma_start(struct ata_queued_cmd *qc)
* unneccessarily delayed for MMIO
*/
}
+EXPORT_SYMBOL_GPL(ata_bmdma_start);
/**
* ata_bmdma_stop - Stop PCI IDE BMDMA transfer
@@ -2314,6 +2411,7 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc)
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
ata_sff_dma_pause(ap);
}
+EXPORT_SYMBOL_GPL(ata_bmdma_stop);
/**
* ata_bmdma_status - Read PCI IDE BMDMA status
@@ -2330,6 +2428,7 @@ u8 ata_bmdma_status(struct ata_port *ap)
{
return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
}
+EXPORT_SYMBOL_GPL(ata_bmdma_status);
/**
* ata_bus_reset - reset host port and associated ATA channel
@@ -2422,6 +2521,7 @@ err_out:
DPRINTK("EXIT\n");
}
+EXPORT_SYMBOL_GPL(ata_bus_reset);
#ifdef CONFIG_PCI
@@ -2449,6 +2549,7 @@ int ata_pci_bmdma_clear_simplex(struct pci_dev *pdev)
return -EOPNOTSUPP;
return 0;
}
+EXPORT_SYMBOL_GPL(ata_pci_bmdma_clear_simplex);
/**
* ata_pci_bmdma_init - acquire PCI BMDMA resources and init ATA host
@@ -2501,11 +2602,12 @@ int ata_pci_bmdma_init(struct ata_host *host)
host->flags |= ATA_HOST_SIMPLEX;
ata_port_desc(ap, "bmdma 0x%llx",
- (unsigned long long)pci_resource_start(pdev, 4) + 8 * i);
+ (unsigned long long)pci_resource_start(pdev, 4) + 8 * i);
}
return 0;
}
+EXPORT_SYMBOL_GPL(ata_pci_bmdma_init);
static int ata_resources_present(struct pci_dev *pdev, int port)
{
@@ -2513,7 +2615,7 @@ static int ata_resources_present(struct pci_dev *pdev, int port)
/* Check the PCI resources for this channel are enabled */
port = port * 2;
- for (i = 0; i < 2; i ++) {
+ for (i = 0; i < 2; i++) {
if (pci_resource_start(pdev, port + i) == 0 ||
pci_resource_len(pdev, port + i) == 0)
return 0;
@@ -2598,6 +2700,7 @@ int ata_pci_sff_init_host(struct ata_host *host)
return 0;
}
+EXPORT_SYMBOL_GPL(ata_pci_sff_init_host);
/**
* ata_pci_sff_prepare_host - helper to prepare native PCI ATA host
@@ -2615,7 +2718,7 @@ int ata_pci_sff_init_host(struct ata_host *host)
* 0 on success, -errno otherwise.
*/
int ata_pci_sff_prepare_host(struct pci_dev *pdev,
- const struct ata_port_info * const * ppi,
+ const struct ata_port_info * const *ppi,
struct ata_host **r_host)
{
struct ata_host *host;
@@ -2645,17 +2748,18 @@ int ata_pci_sff_prepare_host(struct pci_dev *pdev,
*r_host = host;
return 0;
- err_bmdma:
+err_bmdma:
/* This is necessary because PCI and iomap resources are
* merged and releasing the top group won't release the
* acquired resources if some of those have been acquired
* before entering this function.
*/
pcim_iounmap_regions(pdev, 0xf);
- err_out:
+err_out:
devres_release_group(&pdev->dev, NULL);
return rc;
}
+EXPORT_SYMBOL_GPL(ata_pci_sff_prepare_host);
/**
* ata_pci_sff_activate_host - start SFF host, request IRQ and register it
@@ -2741,7 +2845,7 @@ int ata_pci_sff_activate_host(struct ata_host *host,
}
rc = ata_host_register(host, sht);
- out:
+out:
if (rc == 0)
devres_remove_group(dev, NULL);
else
@@ -2749,6 +2853,7 @@ int ata_pci_sff_activate_host(struct ata_host *host,
return rc;
}
+EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host);
/**
* ata_pci_sff_init_one - Initialize/register PCI IDE host controller
@@ -2776,7 +2881,7 @@ int ata_pci_sff_activate_host(struct ata_host *host,
* Zero on success, negative on errno-based value on error.
*/
int ata_pci_sff_init_one(struct pci_dev *pdev,
- const struct ata_port_info * const * ppi,
+ const struct ata_port_info * const *ppi,
struct scsi_host_template *sht, void *host_priv)
{
struct device *dev = &pdev->dev;
@@ -2815,7 +2920,7 @@ int ata_pci_sff_init_one(struct pci_dev *pdev,
pci_set_master(pdev);
rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht);
- out:
+out:
if (rc == 0)
devres_remove_group(&pdev->dev, NULL);
else
@@ -2823,54 +2928,7 @@ int ata_pci_sff_init_one(struct pci_dev *pdev,
return rc;
}
+EXPORT_SYMBOL_GPL(ata_pci_sff_init_one);
#endif /* CONFIG_PCI */
-EXPORT_SYMBOL_GPL(ata_sff_port_ops);
-EXPORT_SYMBOL_GPL(ata_bmdma_port_ops);
-EXPORT_SYMBOL_GPL(ata_sff_qc_prep);
-EXPORT_SYMBOL_GPL(ata_sff_dumb_qc_prep);
-EXPORT_SYMBOL_GPL(ata_sff_dev_select);
-EXPORT_SYMBOL_GPL(ata_sff_check_status);
-EXPORT_SYMBOL_GPL(ata_sff_dma_pause);
-EXPORT_SYMBOL_GPL(ata_sff_pause);
-EXPORT_SYMBOL_GPL(ata_sff_busy_sleep);
-EXPORT_SYMBOL_GPL(ata_sff_wait_ready);
-EXPORT_SYMBOL_GPL(ata_sff_tf_load);
-EXPORT_SYMBOL_GPL(ata_sff_tf_read);
-EXPORT_SYMBOL_GPL(ata_sff_exec_command);
-EXPORT_SYMBOL_GPL(ata_sff_data_xfer);
-EXPORT_SYMBOL_GPL(ata_sff_data_xfer_noirq);
-EXPORT_SYMBOL_GPL(ata_sff_irq_on);
-EXPORT_SYMBOL_GPL(ata_sff_irq_clear);
-EXPORT_SYMBOL_GPL(ata_sff_hsm_move);
-EXPORT_SYMBOL_GPL(ata_sff_qc_issue);
-EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf);
-EXPORT_SYMBOL_GPL(ata_sff_host_intr);
-EXPORT_SYMBOL_GPL(ata_sff_interrupt);
-EXPORT_SYMBOL_GPL(ata_sff_freeze);
-EXPORT_SYMBOL_GPL(ata_sff_thaw);
-EXPORT_SYMBOL_GPL(ata_sff_prereset);
-EXPORT_SYMBOL_GPL(ata_sff_dev_classify);
-EXPORT_SYMBOL_GPL(ata_sff_wait_after_reset);
-EXPORT_SYMBOL_GPL(ata_sff_softreset);
-EXPORT_SYMBOL_GPL(sata_sff_hardreset);
-EXPORT_SYMBOL_GPL(ata_sff_postreset);
-EXPORT_SYMBOL_GPL(ata_sff_error_handler);
-EXPORT_SYMBOL_GPL(ata_sff_post_internal_cmd);
-EXPORT_SYMBOL_GPL(ata_sff_port_start);
-EXPORT_SYMBOL_GPL(ata_sff_std_ports);
-EXPORT_SYMBOL_GPL(ata_bmdma_mode_filter);
-EXPORT_SYMBOL_GPL(ata_bmdma_setup);
-EXPORT_SYMBOL_GPL(ata_bmdma_start);
-EXPORT_SYMBOL_GPL(ata_bmdma_stop);
-EXPORT_SYMBOL_GPL(ata_bmdma_status);
-EXPORT_SYMBOL_GPL(ata_bus_reset);
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL_GPL(ata_pci_bmdma_clear_simplex);
-EXPORT_SYMBOL_GPL(ata_pci_bmdma_init);
-EXPORT_SYMBOL_GPL(ata_pci_sff_init_host);
-EXPORT_SYMBOL_GPL(ata_pci_sff_prepare_host);
-EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host);
-EXPORT_SYMBOL_GPL(ata_pci_sff_init_one);
-#endif /* CONFIG_PCI */
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
index e2e332d8ff95..8b77a9802df1 100644
--- a/drivers/ata/pata_acpi.c
+++ b/drivers/ata/pata_acpi.c
@@ -13,12 +13,6 @@
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <acpi/acpi_bus.h>
-#include <acpi/acnames.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acparser.h>
-#include <acpi/acexcep.h>
-#include <acpi/acmacros.h>
-#include <acpi/actypes.h>
#include <linux/libata.h>
#include <linux/ata.h>
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 73c466e452ca..eb99dbe78081 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -19,7 +19,9 @@
*
* TODO/CHECK
* Cannot have ATAPI on both master & slave for rev < c2 (???) but
- * otherwise should do atapi DMA.
+ * otherwise should do atapi DMA (For now for old we do PIO only for
+ * ATAPI)
+ * Review Sunblade workaround.
*/
#include <linux/kernel.h>
@@ -33,12 +35,14 @@
#include <linux/dmi.h>
#define DRV_NAME "pata_ali"
-#define DRV_VERSION "0.7.5"
+#define DRV_VERSION "0.7.8"
static int ali_atapi_dma = 0;
module_param_named(atapi_dma, ali_atapi_dma, int, 0644);
MODULE_PARM_DESC(atapi_dma, "Enable ATAPI DMA (0=disable, 1=enable)");
+static struct pci_dev *ali_isa_bridge;
+
/*
* Cable special cases
*/
@@ -147,8 +151,7 @@ static void ali_fifo_control(struct ata_port *ap, struct ata_device *adev, int o
pci_read_config_byte(pdev, pio_fifo, &fifo);
fifo &= ~(0x0F << shift);
- if (on)
- fifo |= (on << shift);
+ fifo |= (on << shift);
pci_write_config_byte(pdev, pio_fifo, fifo);
}
@@ -337,6 +340,23 @@ static int ali_check_atapi_dma(struct ata_queued_cmd *qc)
return 0;
}
+static void ali_c2_c3_postreset(struct ata_link *link, unsigned int *classes)
+{
+ u8 r;
+ int port_bit = 4 << link->ap->port_no;
+
+ /* If our bridge is an ALI 1533 then do the extra work */
+ if (ali_isa_bridge) {
+ /* Tristate and re-enable the bus signals */
+ pci_read_config_byte(ali_isa_bridge, 0x58, &r);
+ r &= ~port_bit;
+ pci_write_config_byte(ali_isa_bridge, 0x58, r);
+ r |= port_bit;
+ pci_write_config_byte(ali_isa_bridge, 0x58, r);
+ }
+ ata_sff_postreset(link, classes);
+}
+
static struct scsi_host_template ali_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
@@ -349,10 +369,11 @@ static struct ata_port_operations ali_early_port_ops = {
.inherits = &ata_sff_port_ops,
.cable_detect = ata_cable_40wire,
.set_piomode = ali_set_piomode,
+ .sff_data_xfer = ata_sff_data_xfer32,
};
static const struct ata_port_operations ali_dma_base_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma32_port_ops,
.set_piomode = ali_set_piomode,
.set_dmamode = ali_set_dmamode,
};
@@ -377,6 +398,17 @@ static struct ata_port_operations ali_c2_port_ops = {
.check_atapi_dma = ali_check_atapi_dma,
.cable_detect = ali_c2_cable_detect,
.dev_config = ali_lock_sectors,
+ .postreset = ali_c2_c3_postreset,
+};
+
+/*
+ * Port operations for DMA capable ALi with cable detect
+ */
+static struct ata_port_operations ali_c4_port_ops = {
+ .inherits = &ali_dma_base_ops,
+ .check_atapi_dma = ali_check_atapi_dma,
+ .cable_detect = ali_c2_cable_detect,
+ .dev_config = ali_lock_sectors,
};
/*
@@ -401,52 +433,49 @@ static struct ata_port_operations ali_c5_port_ops = {
static void ali_init_chipset(struct pci_dev *pdev)
{
u8 tmp;
- struct pci_dev *north, *isa_bridge;
+ struct pci_dev *north;
/*
* The chipset revision selects the driver operations and
* mode data.
*/
- if (pdev->revision >= 0x20 && pdev->revision < 0xC2) {
- /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */
- pci_read_config_byte(pdev, 0x4B, &tmp);
- /* Clear CD-ROM DMA write bit */
- tmp &= 0x7F;
- pci_write_config_byte(pdev, 0x4B, tmp);
- } else if (pdev->revision >= 0xC2) {
- /* Enable cable detection logic */
+ if (pdev->revision <= 0x20) {
+ pci_read_config_byte(pdev, 0x53, &tmp);
+ tmp |= 0x03;
+ pci_write_config_byte(pdev, 0x53, tmp);
+ } else {
+ pci_read_config_byte(pdev, 0x4a, &tmp);
+ pci_write_config_byte(pdev, 0x4a, tmp | 0x20);
pci_read_config_byte(pdev, 0x4B, &tmp);
- pci_write_config_byte(pdev, 0x4B, tmp | 0x08);
- }
- north = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
- isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
-
- if (north && north->vendor == PCI_VENDOR_ID_AL && isa_bridge) {
- /* Configure the ALi bridge logic. For non ALi rely on BIOS.
- Set the south bridge enable bit */
- pci_read_config_byte(isa_bridge, 0x79, &tmp);
- if (pdev->revision == 0xC2)
- pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04);
- else if (pdev->revision > 0xC2 && pdev->revision < 0xC5)
- pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02);
- }
- if (pdev->revision >= 0x20) {
+ if (pdev->revision < 0xC2)
+ /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */
+ /* Clear CD-ROM DMA write bit */
+ tmp &= 0x7F;
+ /* Cable and UDMA */
+ pci_write_config_byte(pdev, 0x4B, tmp | 0x09);
/*
* CD_ROM DMA on (0x53 bit 0). Enable this even if we want
* to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control
* via 0x54/55.
*/
pci_read_config_byte(pdev, 0x53, &tmp);
- if (pdev->revision <= 0x20)
- tmp &= ~0x02;
if (pdev->revision >= 0xc7)
tmp |= 0x03;
else
tmp |= 0x01; /* CD_ROM enable for DMA */
pci_write_config_byte(pdev, 0x53, tmp);
}
- pci_dev_put(isa_bridge);
+ north = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
+ if (north && north->vendor == PCI_VENDOR_ID_AL && ali_isa_bridge) {
+ /* Configure the ALi bridge logic. For non ALi rely on BIOS.
+ Set the south bridge enable bit */
+ pci_read_config_byte(ali_isa_bridge, 0x79, &tmp);
+ if (pdev->revision == 0xC2)
+ pci_write_config_byte(ali_isa_bridge, 0x79, tmp | 0x04);
+ else if (pdev->revision > 0xC2 && pdev->revision < 0xC5)
+ pci_write_config_byte(ali_isa_bridge, 0x79, tmp | 0x02);
+ }
pci_dev_put(north);
ata_pci_bmdma_clear_simplex(pdev);
}
@@ -503,7 +532,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
.pio_mask = 0x1f,
.mwdma_mask = 0x07,
.udma_mask = ATA_UDMA5,
- .port_ops = &ali_c2_port_ops
+ .port_ops = &ali_c4_port_ops
};
/* Revision 0xC5 is UDMA133 with LBA48 DMA */
static const struct ata_port_info info_c5 = {
@@ -516,7 +545,6 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
const struct ata_port_info *ppi[] = { NULL, NULL };
u8 tmp;
- struct pci_dev *isa_bridge;
int rc;
rc = pcim_enable_device(pdev);
@@ -543,14 +571,12 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
ali_init_chipset(pdev);
- isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
- if (isa_bridge && pdev->revision >= 0x20 && pdev->revision < 0xC2) {
+ if (ali_isa_bridge && pdev->revision >= 0x20 && pdev->revision < 0xC2) {
/* Are we paired with a UDMA capable chip */
- pci_read_config_byte(isa_bridge, 0x5E, &tmp);
+ pci_read_config_byte(ali_isa_bridge, 0x5E, &tmp);
if ((tmp & 0x1E) == 0x12)
ppi[0] = &info_20_udma;
}
- pci_dev_put(isa_bridge);
return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL);
}
@@ -590,13 +616,20 @@ static struct pci_driver ali_pci_driver = {
static int __init ali_init(void)
{
- return pci_register_driver(&ali_pci_driver);
+ int ret;
+ ali_isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+
+ ret = pci_register_driver(&ali_pci_driver);
+ if (ret < 0)
+ pci_dev_put(ali_isa_bridge);
+ return ret;
}
static void __exit ali_exit(void)
{
pci_unregister_driver(&ali_pci_driver);
+ pci_dev_put(ali_isa_bridge);
}
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 0ec9c7d9fe9d..63719ab9ea44 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -24,7 +24,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_amd"
-#define DRV_VERSION "0.3.10"
+#define DRV_VERSION "0.3.11"
/**
* timing_setup - shared timing computation and load
@@ -345,7 +345,7 @@ static struct scsi_host_template amd_sht = {
};
static const struct ata_port_operations amd_base_port_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma32_port_ops,
.prereset = amd_pre_reset,
};
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 0e2cde8f9973..506adde8ebb3 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -32,21 +32,6 @@ enum {
ATIIXP_IDE_UDMA_MODE = 0x56
};
-static int atiixp_pre_reset(struct ata_link *link, unsigned long deadline)
-{
- struct ata_port *ap = link->ap;
- static const struct pci_bits atiixp_enable_bits[] = {
- { 0x48, 1, 0x01, 0x00 },
- { 0x48, 1, 0x08, 0x00 }
- };
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-
- if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
- return -ENOENT;
-
- return ata_sff_prereset(link, deadline);
-}
-
static int atiixp_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -229,10 +214,9 @@ static struct ata_port_operations atiixp_port_ops = {
.cable_detect = atiixp_cable_detect,
.set_piomode = atiixp_set_piomode,
.set_dmamode = atiixp_set_dmamode,
- .prereset = atiixp_pre_reset,
};
-static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int atiixp_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
static const struct ata_port_info info = {
.flags = ATA_FLAG_SLAVE_POSS,
@@ -241,8 +225,18 @@ static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
.udma_mask = 0x3F,
.port_ops = &atiixp_port_ops
};
- const struct ata_port_info *ppi[] = { &info, NULL };
- return ata_pci_sff_init_one(dev, ppi, &atiixp_sht, NULL);
+ static const struct pci_bits atiixp_enable_bits[] = {
+ { 0x48, 1, 0x01, 0x00 },
+ { 0x48, 1, 0x08, 0x00 }
+ };
+ const struct ata_port_info *ppi[] = { &info, &info };
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (!pci_test_config_bits(pdev, &atiixp_enable_bits[i]))
+ ppi[i] = &ata_dummy_port_info;
+
+ return ata_pci_sff_init_one(pdev, ppi, &atiixp_sht, NULL);
}
static const struct pci_device_id atiixp[] = {
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index e0c4f05d7d57..65c28e5a6cd7 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -30,7 +30,7 @@
#define DRV_VERSION "0.6.2"
struct hpt_clock {
- u8 xfer_speed;
+ u8 xfer_mode;
u32 timing;
};
@@ -189,28 +189,6 @@ static unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask)
return ata_bmdma_mode_filter(adev, mask);
}
-/**
- * hpt36x_find_mode - reset the hpt36x bus
- * @ap: ATA port
- * @speed: transfer mode
- *
- * Return the 32bit register programming information for this channel
- * that matches the speed provided.
- */
-
-static u32 hpt36x_find_mode(struct ata_port *ap, int speed)
-{
- struct hpt_clock *clocks = ap->host->private_data;
-
- while(clocks->xfer_speed) {
- if (clocks->xfer_speed == speed)
- return clocks->timing;
- clocks++;
- }
- BUG();
- return 0xffffffffU; /* silence compiler warning */
-}
-
static int hpt36x_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -226,25 +204,16 @@ static int hpt36x_cable_detect(struct ata_port *ap)
return ATA_CBL_PATA80;
}
-/**
- * hpt366_set_piomode - PIO setup
- * @ap: ATA interface
- * @adev: device on the interface
- *
- * Perform PIO mode setup.
- */
-
-static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void hpt366_set_mode(struct ata_port *ap, struct ata_device *adev,
+ u8 mode)
{
+ struct hpt_clock *clocks = ap->host->private_data;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 addr1, addr2;
- u32 reg;
- u32 mode;
+ u32 addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ u32 addr2 = 0x51 + 4 * ap->port_no;
+ u32 mask, reg;
u8 fast;
- addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
- addr2 = 0x51 + 4 * ap->port_no;
-
/* Fast interrupt prediction disable, hold off interrupt disable */
pci_read_config_byte(pdev, addr2, &fast);
if (fast & 0x80) {
@@ -252,12 +221,43 @@ static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev)
pci_write_config_byte(pdev, addr2, fast);
}
+ /* determine timing mask and find matching clock entry */
+ if (mode < XFER_MW_DMA_0)
+ mask = 0xc1f8ffff;
+ else if (mode < XFER_UDMA_0)
+ mask = 0x303800ff;
+ else
+ mask = 0x30070000;
+
+ while (clocks->xfer_mode) {
+ if (clocks->xfer_mode == mode)
+ break;
+ clocks++;
+ }
+ if (!clocks->xfer_mode)
+ BUG();
+
+ /*
+ * Combine new mode bits with old config bits and disable
+ * on-chip PIO FIFO/buffer (and PIO MST mode as well) to avoid
+ * problems handling I/O errors later.
+ */
pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt36x_find_mode(ap, adev->pio_mode);
- mode &= ~0x8000000; /* No FIFO in PIO */
- mode &= ~0x30070000; /* Leave config bits alone */
- reg &= 0x30070000; /* Strip timing bits */
- pci_write_config_dword(pdev, addr1, reg | mode);
+ reg = ((reg & ~mask) | (clocks->timing & mask)) & ~0xc0000000;
+ pci_write_config_dword(pdev, addr1, reg);
+}
+
+/**
+ * hpt366_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
+
+static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ hpt366_set_mode(ap, adev, adev->pio_mode);
}
/**
@@ -271,28 +271,7 @@ static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev)
static void hpt366_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 addr1, addr2;
- u32 reg;
- u32 mode;
- u8 fast;
-
- addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
- addr2 = 0x51 + 4 * ap->port_no;
-
- /* Fast interrupt prediction disable, hold off interrupt disable */
- pci_read_config_byte(pdev, addr2, &fast);
- if (fast & 0x80) {
- fast &= ~0x80;
- pci_write_config_byte(pdev, addr2, fast);
- }
-
- pci_read_config_dword(pdev, addr1, &reg);
- mode = hpt36x_find_mode(ap, adev->dma_mode);
- mode |= 0x8000000; /* FIFO in MWDMA or UDMA */
- mode &= ~0xC0000000; /* Leave config bits alone */
- reg &= 0xC0000000; /* Strip timing bits */
- pci_write_config_dword(pdev, addr1, reg | mode);
+ hpt366_set_mode(ap, adev, adev->dma_mode);
}
static struct scsi_host_template hpt36x_sht = {
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index f11a320337c0..f19cc645881a 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -23,7 +23,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt3x3"
-#define DRV_VERSION "0.5.3"
+#define DRV_VERSION "0.6.1"
/**
* hpt3x3_set_piomode - PIO setup
@@ -80,14 +80,48 @@ static void hpt3x3_set_dmamode(struct ata_port *ap, struct ata_device *adev)
r2 &= ~(0x11 << dn); /* Clear MWDMA and UDMA bits */
if (adev->dma_mode >= XFER_UDMA_0)
- r2 |= (0x10 << dn); /* Ultra mode */
+ r2 |= (0x01 << dn); /* Ultra mode */
else
- r2 |= (0x01 << dn); /* MWDMA */
+ r2 |= (0x10 << dn); /* MWDMA */
pci_write_config_dword(pdev, 0x44, r1);
pci_write_config_dword(pdev, 0x48, r2);
}
-#endif /* CONFIG_PATA_HPT3X3_DMA */
+
+/**
+ * hpt3x3_freeze - DMA workaround
+ * @ap: port to freeze
+ *
+ * When freezing an HPT3x3 we must stop any pending DMA before
+ * writing to the control register or the chip will hang
+ */
+
+static void hpt3x3_freeze(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+ iowrite8(ioread8(mmio + ATA_DMA_CMD) & ~ ATA_DMA_START,
+ mmio + ATA_DMA_CMD);
+ ata_sff_dma_pause(ap);
+ ata_sff_freeze(ap);
+}
+
+/**
+ * hpt3x3_bmdma_setup - DMA workaround
+ * @qc: Queued command
+ *
+ * When issuing BMDMA we must clean up the error/active bits in
+ * software on this device
+ */
+
+static void hpt3x3_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ u8 r = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ r |= ATA_DMA_INTR | ATA_DMA_ERR;
+ iowrite8(r, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ return ata_bmdma_setup(qc);
+}
/**
* hpt3x3_atapi_dma - ATAPI DMA check
@@ -101,18 +135,23 @@ static int hpt3x3_atapi_dma(struct ata_queued_cmd *qc)
return 1;
}
+#endif /* CONFIG_PATA_HPT3X3_DMA */
+
static struct scsi_host_template hpt3x3_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
static struct ata_port_operations hpt3x3_port_ops = {
.inherits = &ata_bmdma_port_ops,
- .check_atapi_dma= hpt3x3_atapi_dma,
.cable_detect = ata_cable_40wire,
.set_piomode = hpt3x3_set_piomode,
#if defined(CONFIG_PATA_HPT3X3_DMA)
.set_dmamode = hpt3x3_set_dmamode,
+ .bmdma_setup = hpt3x3_bmdma_setup,
+ .check_atapi_dma= hpt3x3_atapi_dma,
+ .freeze = hpt3x3_freeze,
#endif
+
};
/**
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index f828a29d7756..f1bb2f9fecbf 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -80,7 +80,7 @@
#define DRV_NAME "pata_it821x"
-#define DRV_VERSION "0.4.0"
+#define DRV_VERSION "0.4.2"
struct it821x_dev
{
@@ -494,8 +494,6 @@ static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unus
* special. In our case we need to lock the sector count to avoid
* blowing the brains out of the firmware with large LBA48 requests
*
- * FIXME: When FUA appears we need to block FUA too. And SMART and
- * basically we need to filter commands for this chip.
*/
static void it821x_dev_config(struct ata_device *adev)
@@ -890,6 +888,13 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f,
.mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &it821x_rdc_port_ops
+ };
+ static const struct ata_port_info info_rdc_11 = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
/* No UDMA */
.port_ops = &it821x_rdc_port_ops
};
@@ -903,7 +908,11 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return rc;
if (pdev->vendor == PCI_VENDOR_ID_RDC) {
- ppi[0] = &info_rdc;
+ /* Deal with Vortex86SX */
+ if (pdev->revision == 0x11)
+ ppi[0] = &info_rdc_11;
+ else
+ ppi[0] = &info_rdc;
} else {
/* Force the card into bypass mode if so requested */
if (it8212_noraid) {
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 7c8faa48b5f3..aa576cac4d17 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -35,7 +35,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_mpiix"
-#define DRV_VERSION "0.7.6"
+#define DRV_VERSION "0.7.7"
enum {
IDETIM = 0x6C, /* IDE control register */
@@ -146,6 +146,7 @@ static struct ata_port_operations mpiix_port_ops = {
.cable_detect = ata_cable_40wire,
.set_piomode = mpiix_set_piomode,
.prereset = mpiix_pre_reset,
+ .sff_data_xfer = ata_sff_data_xfer32,
};
static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_octeon_cf.c b/drivers/ata/pata_octeon_cf.c
new file mode 100644
index 000000000000..0fe4ef309c62
--- /dev/null
+++ b/drivers/ata/pata_octeon_cf.c
@@ -0,0 +1,965 @@
+/*
+ * Driver for the Octeon bootbus compact flash.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 - 2009 Cavium Networks
+ * Copyright (C) 2008 Wind River Systems
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/libata.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <scsi/scsi_host.h>
+
+#include <asm/octeon/octeon.h>
+
+/*
+ * The Octeon bootbus compact flash interface is connected in at least
+ * 3 different configurations on various evaluation boards:
+ *
+ * -- 8 bits no irq, no DMA
+ * -- 16 bits no irq, no DMA
+ * -- 16 bits True IDE mode with DMA, but no irq.
+ *
+ * In the last case the DMA engine can generate an interrupt when the
+ * transfer is complete. For the first two cases only PIO is supported.
+ *
+ */
+
+#define DRV_NAME "pata_octeon_cf"
+#define DRV_VERSION "2.1"
+
+
+struct octeon_cf_port {
+ struct workqueue_struct *wq;
+ struct delayed_work delayed_finish;
+ struct ata_port *ap;
+ int dma_finished;
+};
+
+static struct scsi_host_template octeon_cf_sht = {
+ ATA_PIO_SHT(DRV_NAME),
+};
+
+/**
+ * Convert nanosecond based time to setting used in the
+ * boot bus timing register, based on timing multiple
+ */
+static unsigned int ns_to_tim_reg(unsigned int tim_mult, unsigned int nsecs)
+{
+ unsigned int val;
+
+ /*
+ * Compute # of eclock periods to get desired duration in
+ * nanoseconds.
+ */
+ val = DIV_ROUND_UP(nsecs * (octeon_get_clock_rate() / 1000000),
+ 1000 * tim_mult);
+
+ return val;
+}
+
+static void octeon_cf_set_boot_reg_cfg(int cs)
+{
+ union cvmx_mio_boot_reg_cfgx reg_cfg;
+ reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs));
+ reg_cfg.s.dmack = 0; /* Don't assert DMACK on access */
+ reg_cfg.s.tim_mult = 2; /* Timing mutiplier 2x */
+ reg_cfg.s.rd_dly = 0; /* Sample on falling edge of BOOT_OE */
+ reg_cfg.s.sam = 0; /* Don't combine write and output enable */
+ reg_cfg.s.we_ext = 0; /* No write enable extension */
+ reg_cfg.s.oe_ext = 0; /* No read enable extension */
+ reg_cfg.s.en = 1; /* Enable this region */
+ reg_cfg.s.orbit = 0; /* Don't combine with previous region */
+ reg_cfg.s.ale = 0; /* Don't do address multiplexing */
+ cvmx_write_csr(CVMX_MIO_BOOT_REG_CFGX(cs), reg_cfg.u64);
+}
+
+/**
+ * Called after libata determines the needed PIO mode. This
+ * function programs the Octeon bootbus regions to support the
+ * timing requirements of the PIO mode.
+ *
+ * @ap: ATA port information
+ * @dev: ATA device
+ */
+static void octeon_cf_set_piomode(struct ata_port *ap, struct ata_device *dev)
+{
+ struct octeon_cf_data *ocd = ap->dev->platform_data;
+ union cvmx_mio_boot_reg_timx reg_tim;
+ int cs = ocd->base_region;
+ int T;
+ struct ata_timing timing;
+
+ int use_iordy;
+ int trh;
+ int pause;
+ /* These names are timing parameters from the ATA spec */
+ int t1;
+ int t2;
+ int t2i;
+
+ T = (int)(2000000000000LL / octeon_get_clock_rate());
+
+ if (ata_timing_compute(dev, dev->pio_mode, &timing, T, T))
+ BUG();
+
+ t1 = timing.setup;
+ if (t1)
+ t1--;
+ t2 = timing.active;
+ if (t2)
+ t2--;
+ t2i = timing.act8b;
+ if (t2i)
+ t2i--;
+
+ trh = ns_to_tim_reg(2, 20);
+ if (trh)
+ trh--;
+
+ pause = timing.cycle - timing.active - timing.setup - trh;
+ if (pause)
+ pause--;
+
+ octeon_cf_set_boot_reg_cfg(cs);
+ if (ocd->dma_engine >= 0)
+ /* True IDE mode, program both chip selects. */
+ octeon_cf_set_boot_reg_cfg(cs + 1);
+
+
+ use_iordy = ata_pio_need_iordy(dev);
+
+ reg_tim.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_TIMX(cs));
+ /* Disable page mode */
+ reg_tim.s.pagem = 0;
+ /* Enable dynamic timing */
+ reg_tim.s.waitm = use_iordy;
+ /* Pages are disabled */
+ reg_tim.s.pages = 0;
+ /* We don't use multiplexed address mode */
+ reg_tim.s.ale = 0;
+ /* Not used */
+ reg_tim.s.page = 0;
+ /* Time after IORDY to coninue to assert the data */
+ reg_tim.s.wait = 0;
+ /* Time to wait to complete the cycle. */
+ reg_tim.s.pause = pause;
+ /* How long to hold after a write to de-assert CE. */
+ reg_tim.s.wr_hld = trh;
+ /* How long to wait after a read to de-assert CE. */
+ reg_tim.s.rd_hld = trh;
+ /* How long write enable is asserted */
+ reg_tim.s.we = t2;
+ /* How long read enable is asserted */
+ reg_tim.s.oe = t2;
+ /* Time after CE that read/write starts */
+ reg_tim.s.ce = ns_to_tim_reg(2, 5);
+ /* Time before CE that address is valid */
+ reg_tim.s.adr = 0;
+
+ /* Program the bootbus region timing for the data port chip select. */
+ cvmx_write_csr(CVMX_MIO_BOOT_REG_TIMX(cs), reg_tim.u64);
+ if (ocd->dma_engine >= 0)
+ /* True IDE mode, program both chip selects. */
+ cvmx_write_csr(CVMX_MIO_BOOT_REG_TIMX(cs + 1), reg_tim.u64);
+}
+
+static void octeon_cf_set_dmamode(struct ata_port *ap, struct ata_device *dev)
+{
+ struct octeon_cf_data *ocd = dev->link->ap->dev->platform_data;
+ union cvmx_mio_boot_dma_timx dma_tim;
+ unsigned int oe_a;
+ unsigned int oe_n;
+ unsigned int dma_ackh;
+ unsigned int dma_arq;
+ unsigned int pause;
+ unsigned int T0, Tkr, Td;
+ unsigned int tim_mult;
+
+ const struct ata_timing *timing;
+
+ timing = ata_timing_find_mode(dev->dma_mode);
+ T0 = timing->cycle;
+ Td = timing->active;
+ Tkr = timing->recover;
+ dma_ackh = timing->dmack_hold;
+
+ dma_tim.u64 = 0;
+ /* dma_tim.s.tim_mult = 0 --> 4x */
+ tim_mult = 4;
+
+ /* not spec'ed, value in eclocks, not affected by tim_mult */
+ dma_arq = 8;
+ pause = 25 - dma_arq * 1000 /
+ (octeon_get_clock_rate() / 1000000); /* Tz */
+
+ oe_a = Td;
+ /* Tkr from cf spec, lengthened to meet T0 */
+ oe_n = max(T0 - oe_a, Tkr);
+
+ dma_tim.s.dmack_pi = 1;
+
+ dma_tim.s.oe_n = ns_to_tim_reg(tim_mult, oe_n);
+ dma_tim.s.oe_a = ns_to_tim_reg(tim_mult, oe_a);
+
+ /*
+ * This is tI, C.F. spec. says 0, but Sony CF card requires
+ * more, we use 20 nS.
+ */
+ dma_tim.s.dmack_s = ns_to_tim_reg(tim_mult, 20);;
+ dma_tim.s.dmack_h = ns_to_tim_reg(tim_mult, dma_ackh);
+
+ dma_tim.s.dmarq = dma_arq;
+ dma_tim.s.pause = ns_to_tim_reg(tim_mult, pause);
+
+ dma_tim.s.rd_dly = 0; /* Sample right on edge */
+
+ /* writes only */
+ dma_tim.s.we_n = ns_to_tim_reg(tim_mult, oe_n);
+ dma_tim.s.we_a = ns_to_tim_reg(tim_mult, oe_a);
+
+ pr_debug("ns to ticks (mult %d) of %d is: %d\n", tim_mult, 60,
+ ns_to_tim_reg(tim_mult, 60));
+ pr_debug("oe_n: %d, oe_a: %d, dmack_s: %d, dmack_h: "
+ "%d, dmarq: %d, pause: %d\n",
+ dma_tim.s.oe_n, dma_tim.s.oe_a, dma_tim.s.dmack_s,
+ dma_tim.s.dmack_h, dma_tim.s.dmarq, dma_tim.s.pause);
+
+ cvmx_write_csr(CVMX_MIO_BOOT_DMA_TIMX(ocd->dma_engine),
+ dma_tim.u64);
+
+}
+
+/**
+ * Handle an 8 bit I/O request.
+ *
+ * @dev: Device to access
+ * @buffer: Data buffer
+ * @buflen: Length of the buffer.
+ * @rw: True to write.
+ */
+static unsigned int octeon_cf_data_xfer8(struct ata_device *dev,
+ unsigned char *buffer,
+ unsigned int buflen,
+ int rw)
+{
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned long words;
+ int count;
+
+ words = buflen;
+ if (rw) {
+ count = 16;
+ while (words--) {
+ iowrite8(*buffer, data_addr);
+ buffer++;
+ /*
+ * Every 16 writes do a read so the bootbus
+ * FIFO doesn't fill up.
+ */
+ if (--count == 0) {
+ ioread8(ap->ioaddr.altstatus_addr);
+ count = 16;
+ }
+ }
+ } else {
+ ioread8_rep(data_addr, buffer, words);
+ }
+ return buflen;
+}
+
+/**
+ * Handle a 16 bit I/O request.
+ *
+ * @dev: Device to access
+ * @buffer: Data buffer
+ * @buflen: Length of the buffer.
+ * @rw: True to write.
+ */
+static unsigned int octeon_cf_data_xfer16(struct ata_device *dev,
+ unsigned char *buffer,
+ unsigned int buflen,
+ int rw)
+{
+ struct ata_port *ap = dev->link->ap;
+ void __iomem *data_addr = ap->ioaddr.data_addr;
+ unsigned long words;
+ int count;
+
+ words = buflen / 2;
+ if (rw) {
+ count = 16;
+ while (words--) {
+ iowrite16(*(uint16_t *)buffer, data_addr);
+ buffer += sizeof(uint16_t);
+ /*
+ * Every 16 writes do a read so the bootbus
+ * FIFO doesn't fill up.
+ */
+ if (--count == 0) {
+ ioread8(ap->ioaddr.altstatus_addr);
+ count = 16;
+ }
+ }
+ } else {
+ while (words--) {
+ *(uint16_t *)buffer = ioread16(data_addr);
+ buffer += sizeof(uint16_t);
+ }
+ }
+ /* Transfer trailing 1 byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ __le16 align_buf[1] = { 0 };
+
+ if (rw == READ) {
+ align_buf[0] = cpu_to_le16(ioread16(data_addr));
+ memcpy(buffer, align_buf, 1);
+ } else {
+ memcpy(align_buf, buffer, 1);
+ iowrite16(le16_to_cpu(align_buf[0]), data_addr);
+ }
+ words++;
+ }
+ return buflen;
+}
+
+/**
+ * Read the taskfile for 16bit non-True IDE only.
+ */
+static void octeon_cf_tf_read16(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ u16 blob;
+ /* The base of the registers is at ioaddr.data_addr. */
+ void __iomem *base = ap->ioaddr.data_addr;
+
+ blob = __raw_readw(base + 0xc);
+ tf->feature = blob >> 8;
+
+ blob = __raw_readw(base + 2);
+ tf->nsect = blob & 0xff;
+ tf->lbal = blob >> 8;
+
+ blob = __raw_readw(base + 4);
+ tf->lbam = blob & 0xff;
+ tf->lbah = blob >> 8;
+
+ blob = __raw_readw(base + 6);
+ tf->device = blob & 0xff;
+ tf->command = blob >> 8;
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ if (likely(ap->ioaddr.ctl_addr)) {
+ iowrite8(tf->ctl | ATA_HOB, ap->ioaddr.ctl_addr);
+
+ blob = __raw_readw(base + 0xc);
+ tf->hob_feature = blob >> 8;
+
+ blob = __raw_readw(base + 2);
+ tf->hob_nsect = blob & 0xff;
+ tf->hob_lbal = blob >> 8;
+
+ blob = __raw_readw(base + 4);
+ tf->hob_lbam = blob & 0xff;
+ tf->hob_lbah = blob >> 8;
+
+ iowrite8(tf->ctl, ap->ioaddr.ctl_addr);
+ ap->last_ctl = tf->ctl;
+ } else {
+ WARN_ON(1);
+ }
+ }
+}
+
+static u8 octeon_cf_check_status16(struct ata_port *ap)
+{
+ u16 blob;
+ void __iomem *base = ap->ioaddr.data_addr;
+
+ blob = __raw_readw(base + 6);
+ return blob >> 8;
+}
+
+static int octeon_cf_softreset16(struct ata_link *link, unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ void __iomem *base = ap->ioaddr.data_addr;
+ int rc;
+ u8 err;
+
+ DPRINTK("about to softreset\n");
+ __raw_writew(ap->ctl, base + 0xe);
+ udelay(20);
+ __raw_writew(ap->ctl | ATA_SRST, base + 0xe);
+ udelay(20);
+ __raw_writew(ap->ctl, base + 0xe);
+
+ rc = ata_sff_wait_after_reset(link, 1, deadline);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_sff_dev_classify(&link->device[0], 1, &err);
+ DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
+ return 0;
+}
+
+/**
+ * Load the taskfile for 16bit non-True IDE only. The device_addr is
+ * not loaded, we do this as part of octeon_cf_exec_command16.
+ */
+static void octeon_cf_tf_load16(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+ /* The base of the registers is at ioaddr.data_addr. */
+ void __iomem *base = ap->ioaddr.data_addr;
+
+ if (tf->ctl != ap->last_ctl) {
+ iowrite8(tf->ctl, ap->ioaddr.ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ __raw_writew(tf->hob_feature << 8, base + 0xc);
+ __raw_writew(tf->hob_nsect | tf->hob_lbal << 8, base + 2);
+ __raw_writew(tf->hob_lbam | tf->hob_lbah << 8, base + 4);
+ VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+ tf->hob_feature,
+ tf->hob_nsect,
+ tf->hob_lbal,
+ tf->hob_lbam,
+ tf->hob_lbah);
+ }
+ if (is_addr) {
+ __raw_writew(tf->feature << 8, base + 0xc);
+ __raw_writew(tf->nsect | tf->lbal << 8, base + 2);
+ __raw_writew(tf->lbam | tf->lbah << 8, base + 4);
+ VPRINTK("feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+ tf->feature,
+ tf->nsect,
+ tf->lbal,
+ tf->lbam,
+ tf->lbah);
+ }
+ ata_wait_idle(ap);
+}
+
+
+static void octeon_cf_dev_select(struct ata_port *ap, unsigned int device)
+{
+/* There is only one device, do nothing. */
+ return;
+}
+
+/*
+ * Issue ATA command to host controller. The device_addr is also sent
+ * as it must be written in a combined write with the command.
+ */
+static void octeon_cf_exec_command16(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ /* The base of the registers is at ioaddr.data_addr. */
+ void __iomem *base = ap->ioaddr.data_addr;
+ u16 blob;
+
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ VPRINTK("device 0x%X\n", tf->device);
+ blob = tf->device;
+ } else {
+ blob = 0;
+ }
+
+ DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+ blob |= (tf->command << 8);
+ __raw_writew(blob, base + 6);
+
+
+ ata_wait_idle(ap);
+}
+
+static u8 octeon_cf_irq_on(struct ata_port *ap)
+{
+ return 0;
+}
+
+static void octeon_cf_irq_clear(struct ata_port *ap)
+{
+ return;
+}
+
+static void octeon_cf_dma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct octeon_cf_port *cf_port;
+
+ cf_port = (struct octeon_cf_port *)ap->private_data;
+ DPRINTK("ENTER\n");
+ /* issue r/w command */
+ qc->cursg = qc->sg;
+ cf_port->dma_finished = 0;
+ ap->ops->sff_exec_command(ap, &qc->tf);
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * Start a DMA transfer that was already setup
+ *
+ * @qc: Information about the DMA
+ */
+static void octeon_cf_dma_start(struct ata_queued_cmd *qc)
+{
+ struct octeon_cf_data *ocd = qc->ap->dev->platform_data;
+ union cvmx_mio_boot_dma_cfgx mio_boot_dma_cfg;
+ union cvmx_mio_boot_dma_intx mio_boot_dma_int;
+ struct scatterlist *sg;
+
+ VPRINTK("%d scatterlists\n", qc->n_elem);
+
+ /* Get the scatter list entry we need to DMA into */
+ sg = qc->cursg;
+ BUG_ON(!sg);
+
+ /*
+ * Clear the DMA complete status.
+ */
+ mio_boot_dma_int.u64 = 0;
+ mio_boot_dma_int.s.done = 1;
+ cvmx_write_csr(CVMX_MIO_BOOT_DMA_INTX(ocd->dma_engine),
+ mio_boot_dma_int.u64);
+
+ /* Enable the interrupt. */
+ cvmx_write_csr(CVMX_MIO_BOOT_DMA_INT_ENX(ocd->dma_engine),
+ mio_boot_dma_int.u64);
+
+ /* Set the direction of the DMA */
+ mio_boot_dma_cfg.u64 = 0;
+ mio_boot_dma_cfg.s.en = 1;
+ mio_boot_dma_cfg.s.rw = ((qc->tf.flags & ATA_TFLAG_WRITE) != 0);
+
+ /*
+ * Don't stop the DMA if the device deasserts DMARQ. Many
+ * compact flashes deassert DMARQ for a short time between
+ * sectors. Instead of stopping and restarting the DMA, we'll
+ * let the hardware do it. If the DMA is really stopped early
+ * due to an error condition, a later timeout will force us to
+ * stop.
+ */
+ mio_boot_dma_cfg.s.clr = 0;
+
+ /* Size is specified in 16bit words and minus one notation */
+ mio_boot_dma_cfg.s.size = sg_dma_len(sg) / 2 - 1;
+
+ /* We need to swap the high and low bytes of every 16 bits */
+ mio_boot_dma_cfg.s.swap8 = 1;
+
+ mio_boot_dma_cfg.s.adr = sg_dma_address(sg);
+
+ VPRINTK("%s %d bytes address=%p\n",
+ (mio_boot_dma_cfg.s.rw) ? "write" : "read", sg->length,
+ (void *)(unsigned long)mio_boot_dma_cfg.s.adr);
+
+ cvmx_write_csr(CVMX_MIO_BOOT_DMA_CFGX(ocd->dma_engine),
+ mio_boot_dma_cfg.u64);
+}
+
+/**
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ *
+ */
+static unsigned int octeon_cf_dma_finished(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
+{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ struct octeon_cf_data *ocd = ap->dev->platform_data;
+ union cvmx_mio_boot_dma_cfgx dma_cfg;
+ union cvmx_mio_boot_dma_intx dma_int;
+ struct octeon_cf_port *cf_port;
+ u8 status;
+
+ VPRINTK("ata%u: protocol %d task_state %d\n",
+ ap->print_id, qc->tf.protocol, ap->hsm_task_state);
+
+
+ if (ap->hsm_task_state != HSM_ST_LAST)
+ return 0;
+
+ cf_port = (struct octeon_cf_port *)ap->private_data;
+
+ dma_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_DMA_CFGX(ocd->dma_engine));
+ if (dma_cfg.s.size != 0xfffff) {
+ /* Error, the transfer was not complete. */
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ ap->hsm_task_state = HSM_ST_ERR;
+ }
+
+ /* Stop and clear the dma engine. */
+ dma_cfg.u64 = 0;
+ dma_cfg.s.size = -1;
+ cvmx_write_csr(CVMX_MIO_BOOT_DMA_CFGX(ocd->dma_engine), dma_cfg.u64);
+
+ /* Disable the interrupt. */
+ dma_int.u64 = 0;
+ cvmx_write_csr(CVMX_MIO_BOOT_DMA_INT_ENX(ocd->dma_engine), dma_int.u64);
+
+ /* Clear the DMA complete status */
+ dma_int.s.done = 1;
+ cvmx_write_csr(CVMX_MIO_BOOT_DMA_INTX(ocd->dma_engine), dma_int.u64);
+
+ status = ap->ops->sff_check_status(ap);
+
+ ata_sff_hsm_move(ap, qc, status, 0);
+
+ if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA))
+ ata_ehi_push_desc(ehi, "DMA stat 0x%x", status);
+
+ return 1;
+}
+
+/*
+ * Check if any queued commands have more DMAs, if so start the next
+ * transfer, else do end of transfer handling.
+ */
+static irqreturn_t octeon_cf_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ struct octeon_cf_port *cf_port;
+ int i;
+ unsigned int handled = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ DPRINTK("ENTER\n");
+ for (i = 0; i < host->n_ports; i++) {
+ u8 status;
+ struct ata_port *ap;
+ struct ata_queued_cmd *qc;
+ union cvmx_mio_boot_dma_intx dma_int;
+ union cvmx_mio_boot_dma_cfgx dma_cfg;
+ struct octeon_cf_data *ocd;
+
+ ap = host->ports[i];
+ ocd = ap->dev->platform_data;
+ if (!ap || (ap->flags & ATA_FLAG_DISABLED))
+ continue;
+
+ ocd = ap->dev->platform_data;
+ cf_port = (struct octeon_cf_port *)ap->private_data;
+ dma_int.u64 =
+ cvmx_read_csr(CVMX_MIO_BOOT_DMA_INTX(ocd->dma_engine));
+ dma_cfg.u64 =
+ cvmx_read_csr(CVMX_MIO_BOOT_DMA_CFGX(ocd->dma_engine));
+
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
+ (qc->flags & ATA_QCFLAG_ACTIVE)) {
+ if (dma_int.s.done && !dma_cfg.s.en) {
+ if (!sg_is_last(qc->cursg)) {
+ qc->cursg = sg_next(qc->cursg);
+ handled = 1;
+ octeon_cf_dma_start(qc);
+ continue;
+ } else {
+ cf_port->dma_finished = 1;
+ }
+ }
+ if (!cf_port->dma_finished)
+ continue;
+ status = ioread8(ap->ioaddr.altstatus_addr);
+ if (status & (ATA_BUSY | ATA_DRQ)) {
+ /*
+ * We are busy, try to handle it
+ * later. This is the DMA finished
+ * interrupt, and it could take a
+ * little while for the card to be
+ * ready for more commands.
+ */
+ /* Clear DMA irq. */
+ dma_int.u64 = 0;
+ dma_int.s.done = 1;
+ cvmx_write_csr(CVMX_MIO_BOOT_DMA_INTX(ocd->dma_engine),
+ dma_int.u64);
+
+ queue_delayed_work(cf_port->wq,
+ &cf_port->delayed_finish, 1);
+ handled = 1;
+ } else {
+ handled |= octeon_cf_dma_finished(ap, qc);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+ DPRINTK("EXIT\n");
+ return IRQ_RETVAL(handled);
+}
+
+static void octeon_cf_delayed_finish(struct work_struct *work)
+{
+ struct octeon_cf_port *cf_port = container_of(work,
+ struct octeon_cf_port,
+ delayed_finish.work);
+ struct ata_port *ap = cf_port->ap;
+ struct ata_host *host = ap->host;
+ struct ata_queued_cmd *qc;
+ unsigned long flags;
+ u8 status;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ /*
+ * If the port is not waiting for completion, it must have
+ * handled it previously. The hsm_task_state is
+ * protected by host->lock.
+ */
+ if (ap->hsm_task_state != HSM_ST_LAST || !cf_port->dma_finished)
+ goto out;
+
+ status = ioread8(ap->ioaddr.altstatus_addr);
+ if (status & (ATA_BUSY | ATA_DRQ)) {
+ /* Still busy, try again. */
+ queue_delayed_work(cf_port->wq,
+ &cf_port->delayed_finish, 1);
+ goto out;
+ }
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
+ (qc->flags & ATA_QCFLAG_ACTIVE))
+ octeon_cf_dma_finished(ap, qc);
+out:
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void octeon_cf_dev_config(struct ata_device *dev)
+{
+ /*
+ * A maximum of 2^20 - 1 16 bit transfers are possible with
+ * the bootbus DMA. So we need to throttle max_sectors to
+ * (2^12 - 1 == 4095) to assure that this can never happen.
+ */
+ dev->max_sectors = min(dev->max_sectors, 4095U);
+}
+
+/*
+ * Trap if driver tries to do standard bmdma commands. They are not
+ * supported.
+ */
+static void unreachable_qc(struct ata_queued_cmd *qc)
+{
+ BUG();
+}
+
+static u8 unreachable_port(struct ata_port *ap)
+{
+ BUG();
+}
+
+/*
+ * We don't do ATAPI DMA so return 0.
+ */
+static int octeon_cf_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ return 0;
+}
+
+static unsigned int octeon_cf_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_DMA:
+ WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING);
+
+ ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */
+ octeon_cf_dma_setup(qc); /* set up dma */
+ octeon_cf_dma_start(qc); /* initiate dma */
+ ap->hsm_task_state = HSM_ST_LAST;
+ break;
+
+ case ATAPI_PROT_DMA:
+ dev_err(ap->dev, "Error, ATAPI not supported\n");
+ BUG();
+
+ default:
+ return ata_sff_qc_issue(qc);
+ }
+
+ return 0;
+}
+
+static struct ata_port_operations octeon_cf_ops = {
+ .inherits = &ata_sff_port_ops,
+ .check_atapi_dma = octeon_cf_check_atapi_dma,
+ .qc_prep = ata_noop_qc_prep,
+ .qc_issue = octeon_cf_qc_issue,
+ .sff_dev_select = octeon_cf_dev_select,
+ .sff_irq_on = octeon_cf_irq_on,
+ .sff_irq_clear = octeon_cf_irq_clear,
+ .bmdma_setup = unreachable_qc,
+ .bmdma_start = unreachable_qc,
+ .bmdma_stop = unreachable_qc,
+ .bmdma_status = unreachable_port,
+ .cable_detect = ata_cable_40wire,
+ .set_piomode = octeon_cf_set_piomode,
+ .set_dmamode = octeon_cf_set_dmamode,
+ .dev_config = octeon_cf_dev_config,
+};
+
+static int __devinit octeon_cf_probe(struct platform_device *pdev)
+{
+ struct resource *res_cs0, *res_cs1;
+
+ void __iomem *cs0;
+ void __iomem *cs1 = NULL;
+ struct ata_host *host;
+ struct ata_port *ap;
+ struct octeon_cf_data *ocd;
+ int irq = 0;
+ irq_handler_t irq_handler = NULL;
+ void __iomem *base;
+ struct octeon_cf_port *cf_port;
+
+ res_cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res_cs0)
+ return -EINVAL;
+
+ ocd = pdev->dev.platform_data;
+
+ cs0 = devm_ioremap_nocache(&pdev->dev, res_cs0->start,
+ res_cs0->end - res_cs0->start + 1);
+
+ if (!cs0)
+ return -ENOMEM;
+
+ /* Determine from availability of DMA if True IDE mode or not */
+ if (ocd->dma_engine >= 0) {
+ res_cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res_cs1)
+ return -EINVAL;
+
+ cs1 = devm_ioremap_nocache(&pdev->dev, res_cs1->start,
+ res_cs0->end - res_cs1->start + 1);
+
+ if (!cs1)
+ return -ENOMEM;
+ }
+
+ cf_port = kzalloc(sizeof(*cf_port), GFP_KERNEL);
+ if (!cf_port)
+ return -ENOMEM;
+
+ /* allocate host */
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ goto free_cf_port;
+
+ ap = host->ports[0];
+ ap->private_data = cf_port;
+ cf_port->ap = ap;
+ ap->ops = &octeon_cf_ops;
+ ap->pio_mask = 0x7f; /* Support PIO 0-6 */
+ ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY
+ | ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING;
+
+ base = cs0 + ocd->base_region_bias;
+ if (!ocd->is16bit) {
+ ap->ioaddr.cmd_addr = base;
+ ata_sff_std_ports(&ap->ioaddr);
+
+ ap->ioaddr.altstatus_addr = base + 0xe;
+ ap->ioaddr.ctl_addr = base + 0xe;
+ octeon_cf_ops.sff_data_xfer = octeon_cf_data_xfer8;
+ } else if (cs1) {
+ /* Presence of cs1 indicates True IDE mode. */
+ ap->ioaddr.cmd_addr = base + (ATA_REG_CMD << 1) + 1;
+ ap->ioaddr.data_addr = base + (ATA_REG_DATA << 1);
+ ap->ioaddr.error_addr = base + (ATA_REG_ERR << 1) + 1;
+ ap->ioaddr.feature_addr = base + (ATA_REG_FEATURE << 1) + 1;
+ ap->ioaddr.nsect_addr = base + (ATA_REG_NSECT << 1) + 1;
+ ap->ioaddr.lbal_addr = base + (ATA_REG_LBAL << 1) + 1;
+ ap->ioaddr.lbam_addr = base + (ATA_REG_LBAM << 1) + 1;
+ ap->ioaddr.lbah_addr = base + (ATA_REG_LBAH << 1) + 1;
+ ap->ioaddr.device_addr = base + (ATA_REG_DEVICE << 1) + 1;
+ ap->ioaddr.status_addr = base + (ATA_REG_STATUS << 1) + 1;
+ ap->ioaddr.command_addr = base + (ATA_REG_CMD << 1) + 1;
+ ap->ioaddr.altstatus_addr = cs1 + (6 << 1) + 1;
+ ap->ioaddr.ctl_addr = cs1 + (6 << 1) + 1;
+ octeon_cf_ops.sff_data_xfer = octeon_cf_data_xfer16;
+
+ ap->mwdma_mask = 0x1f; /* Support MWDMA 0-4 */
+ irq = platform_get_irq(pdev, 0);
+ irq_handler = octeon_cf_interrupt;
+
+ /* True IDE mode needs delayed work to poll for not-busy. */
+ cf_port->wq = create_singlethread_workqueue(DRV_NAME);
+ if (!cf_port->wq)
+ goto free_cf_port;
+ INIT_DELAYED_WORK(&cf_port->delayed_finish,
+ octeon_cf_delayed_finish);
+
+ } else {
+ /* 16 bit but not True IDE */
+ octeon_cf_ops.sff_data_xfer = octeon_cf_data_xfer16;
+ octeon_cf_ops.softreset = octeon_cf_softreset16;
+ octeon_cf_ops.sff_check_status = octeon_cf_check_status16;
+ octeon_cf_ops.sff_tf_read = octeon_cf_tf_read16;
+ octeon_cf_ops.sff_tf_load = octeon_cf_tf_load16;
+ octeon_cf_ops.sff_exec_command = octeon_cf_exec_command16;
+
+ ap->ioaddr.data_addr = base + ATA_REG_DATA;
+ ap->ioaddr.nsect_addr = base + ATA_REG_NSECT;
+ ap->ioaddr.lbal_addr = base + ATA_REG_LBAL;
+ ap->ioaddr.ctl_addr = base + 0xe;
+ ap->ioaddr.altstatus_addr = base + 0xe;
+ }
+
+ ata_port_desc(ap, "cmd %p ctl %p", base, ap->ioaddr.ctl_addr);
+
+
+ dev_info(&pdev->dev, "version " DRV_VERSION" %d bit%s.\n",
+ (ocd->is16bit) ? 16 : 8,
+ (cs1) ? ", True IDE" : "");
+
+
+ return ata_host_activate(host, irq, irq_handler, 0, &octeon_cf_sht);
+
+free_cf_port:
+ kfree(cf_port);
+ return -ENOMEM;
+}
+
+static struct platform_driver octeon_cf_driver = {
+ .probe = octeon_cf_probe,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init octeon_cf_init(void)
+{
+ return platform_driver_register(&octeon_cf_driver);
+}
+
+
+MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
+MODULE_DESCRIPTION("low-level driver for Cavium OCTEON Compact Flash PATA");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);
+
+module_init(octeon_cf_init);
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 6afa07a37648..d8d743af3225 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -186,7 +186,7 @@ EXPORT_SYMBOL_GPL(__pata_platform_probe);
* A platform bus ATA device has been unplugged. Perform the needed
* cleanup. Also called on module unload for any active devices.
*/
-int __devexit __pata_platform_remove(struct device *dev)
+int __pata_platform_remove(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index 83580a59db58..9e764e5747e6 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -32,7 +32,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_sil680"
-#define DRV_VERSION "0.4.8"
+#define DRV_VERSION "0.4.9"
#define SIL680_MMIO_BAR 5
@@ -195,7 +195,7 @@ static struct scsi_host_template sil680_sht = {
};
static struct ata_port_operations sil680_port_ops = {
- .inherits = &ata_bmdma_port_ops,
+ .inherits = &ata_bmdma32_port_ops,
.cable_detect = sil680_cable_detect,
.set_piomode = sil680_set_piomode,
.set_dmamode = sil680_set_dmamode,
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 1a56db92ff7a..55bc88c1707b 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -1288,7 +1288,7 @@ static const struct ata_port_info sata_fsl_port_info[] = {
static int sata_fsl_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
- int retval = 0;
+ int retval = -ENXIO;
void __iomem *hcr_base = NULL;
void __iomem *ssr_base = NULL;
void __iomem *csr_base = NULL;
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index ccee930f1e12..2590c2279fa7 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -51,13 +51,6 @@ struct sil24_sge {
__le32 flags;
};
-/*
- * Port multiplier
- */
-struct sil24_port_multiplier {
- __le32 diag;
- __le32 sactive;
-};
enum {
SIL24_HOST_BAR = 0,
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index c18935f0bda2..5c62da9cd491 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -92,6 +92,8 @@ static const struct pci_device_id svia_pci_tbl[] = {
{ PCI_VDEVICE(VIA, 0x5372), vt6420 },
{ PCI_VDEVICE(VIA, 0x7372), vt6420 },
{ PCI_VDEVICE(VIA, 0x5287), vt8251 }, /* 2 sata chnls (Master/Slave) */
+ { PCI_VDEVICE(VIA, 0x9000), vt8251 },
+ { PCI_VDEVICE(VIA, 0x9040), vt8251 },
{ } /* terminate list */
};
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 088885ed51b9..e1c7611e9144 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -64,7 +64,7 @@
#include <linux/jiffies.h>
#include "iphase.h"
#include "suni.h"
-#define swap(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8))
+#define swap_byte_order(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8))
#define PRIV(dev) ((struct suni_priv *) dev->phy_data)
@@ -1306,7 +1306,7 @@ static void rx_dle_intr(struct atm_dev *dev)
// get real pkt length pwang_test
trailer = (struct cpcs_trailer*)((u_char *)skb->data +
skb->len - sizeof(*trailer));
- length = swap(trailer->length);
+ length = swap_byte_order(trailer->length);
if ((length > iadev->rx_buf_sz) || (length >
(skb->len - sizeof(struct cpcs_trailer))))
{
@@ -2995,7 +2995,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
skb->len, PCI_DMA_TODEVICE);
wr_ptr->local_pkt_addr = (buf_desc_ptr->buf_start_hi << 16) |
buf_desc_ptr->buf_start_lo;
- /* wr_ptr->bytes = swap(total_len); didn't seem to affect ?? */
+ /* wr_ptr->bytes = swap_byte_order(total_len); didn't seem to affect?? */
wr_ptr->bytes = skb->len;
/* hw bug - DLEs of 0x2d, 0x2e, 0x2f cause DMA lockup */
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index d8e8c49c0cbd..8f006f96ff53 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -54,7 +54,7 @@ config FIRMWARE_IN_KERNEL
such firmware, and do not wish to use an initrd.
This single option controls the inclusion of firmware for
- every driver which uses request_firmare() and ships its
+ every driver which uses request_firmware() and ships its
firmware in the kernel source tree, to avoid a proliferation
of 'Include firmware for xxx device' options.
diff --git a/drivers/base/base.h b/drivers/base/base.h
index b676f8f801f8..0a5f055dffba 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -63,32 +63,6 @@ struct class_private {
#define to_class(obj) \
container_of(obj, struct class_private, class_subsys.kobj)
-/**
- * struct device_private - structure to hold the private to the driver core portions of the device structure.
- *
- * @klist_children - klist containing all children of this device
- * @knode_parent - node in sibling list
- * @knode_driver - node in driver list
- * @knode_bus - node in bus list
- * @device - pointer back to the struct class that this structure is
- * associated with.
- *
- * Nothing outside of the driver core should ever touch these fields.
- */
-struct device_private {
- struct klist klist_children;
- struct klist_node knode_parent;
- struct klist_node knode_driver;
- struct klist_node knode_bus;
- struct device *device;
-};
-#define to_device_private_parent(obj) \
- container_of(obj, struct device_private, knode_parent)
-#define to_device_private_driver(obj) \
- container_of(obj, struct device_private, knode_driver)
-#define to_device_private_bus(obj) \
- container_of(obj, struct device_private, knode_bus)
-
/* initialisation functions */
extern int devices_init(void);
extern int buses_init(void);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 0f0a50444672..83f32b891fa9 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -253,14 +253,7 @@ static ssize_t store_drivers_probe(struct bus_type *bus,
static struct device *next_device(struct klist_iter *i)
{
struct klist_node *n = klist_next(i);
- struct device *dev = NULL;
- struct device_private *dev_prv;
-
- if (n) {
- dev_prv = to_device_private_bus(n);
- dev = dev_prv->device;
- }
- return dev;
+ return n ? container_of(n, struct device, knode_bus) : NULL;
}
/**
@@ -293,7 +286,7 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start,
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
- (start ? &start->p->knode_bus : NULL));
+ (start ? &start->knode_bus : NULL));
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i);
@@ -327,7 +320,7 @@ struct device *bus_find_device(struct bus_type *bus,
return NULL;
klist_iter_init_node(&bus->p->klist_devices, &i,
- (start ? &start->p->knode_bus : NULL));
+ (start ? &start->knode_bus : NULL));
while ((dev = next_device(&i)))
if (match(dev, data) && get_device(dev))
break;
@@ -514,8 +507,7 @@ void bus_attach_device(struct device *dev)
ret = device_attach(dev);
WARN_ON(ret < 0);
if (ret >= 0)
- klist_add_tail(&dev->p->knode_bus,
- &bus->p->klist_devices);
+ klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
}
}
@@ -536,8 +528,8 @@ void bus_remove_device(struct device *dev)
sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
dev_name(dev));
device_remove_attrs(dev->bus, dev);
- if (klist_node_attached(&dev->p->knode_bus))
- klist_del(&dev->p->knode_bus);
+ if (klist_node_attached(&dev->knode_bus))
+ klist_del(&dev->knode_bus);
pr_debug("bus: '%s': remove device %s\n",
dev->bus->name, dev_name(dev));
@@ -839,16 +831,14 @@ static void bus_remove_attrs(struct bus_type *bus)
static void klist_devices_get(struct klist_node *n)
{
- struct device_private *dev_prv = to_device_private_bus(n);
- struct device *dev = dev_prv->device;
+ struct device *dev = container_of(n, struct device, knode_bus);
get_device(dev);
}
static void klist_devices_put(struct klist_node *n)
{
- struct device_private *dev_prv = to_device_private_bus(n);
- struct device *dev = dev_prv->device;
+ struct device *dev = container_of(n, struct device, knode_bus);
put_device(dev);
}
@@ -1003,20 +993,18 @@ static void device_insertion_sort_klist(struct device *a, struct list_head *list
{
struct list_head *pos;
struct klist_node *n;
- struct device_private *dev_prv;
struct device *b;
list_for_each(pos, list) {
n = container_of(pos, struct klist_node, n_node);
- dev_prv = to_device_private_bus(n);
- b = dev_prv->device;
+ b = container_of(n, struct device, knode_bus);
if (compare(a, b) <= 0) {
- list_move_tail(&a->p->knode_bus.n_node,
- &b->p->knode_bus.n_node);
+ list_move_tail(&a->knode_bus.n_node,
+ &b->knode_bus.n_node);
return;
}
}
- list_move_tail(&a->p->knode_bus.n_node, list);
+ list_move_tail(&a->knode_bus.n_node, list);
}
void bus_sort_breadthfirst(struct bus_type *bus,
@@ -1026,7 +1014,6 @@ void bus_sort_breadthfirst(struct bus_type *bus,
LIST_HEAD(sorted_devices);
struct list_head *pos, *tmp;
struct klist_node *n;
- struct device_private *dev_prv;
struct device *dev;
struct klist *device_klist;
@@ -1035,8 +1022,7 @@ void bus_sort_breadthfirst(struct bus_type *bus,
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_prv = to_device_private_bus(n);
- dev = dev_prv->device;
+ dev = container_of(n, struct device, knode_bus);
device_insertion_sort_klist(dev, &sorted_devices, compare);
}
list_splice(&sorted_devices, &device_klist->k_list);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 61df508fa62b..8079afca4972 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -109,7 +109,6 @@ static struct sysfs_ops dev_sysfs_ops = {
static void device_release(struct kobject *kobj)
{
struct device *dev = to_dev(kobj);
- struct device_private *p = dev->p;
if (dev->release)
dev->release(dev);
@@ -121,7 +120,6 @@ static void device_release(struct kobject *kobj)
WARN(1, KERN_ERR "Device '%s' does not have a release() "
"function, it is broken and must be fixed.\n",
dev_name(dev));
- kfree(p);
}
static struct kobj_type device_ktype = {
@@ -509,16 +507,14 @@ EXPORT_SYMBOL_GPL(device_schedule_callback_owner);
static void klist_children_get(struct klist_node *n)
{
- struct device_private *p = to_device_private_parent(n);
- struct device *dev = p->device;
+ struct device *dev = container_of(n, struct device, knode_parent);
get_device(dev);
}
static void klist_children_put(struct klist_node *n)
{
- struct device_private *p = to_device_private_parent(n);
- struct device *dev = p->device;
+ struct device *dev = container_of(n, struct device, knode_parent);
put_device(dev);
}
@@ -540,15 +536,9 @@ static void klist_children_put(struct klist_node *n)
*/
void device_initialize(struct device *dev)
{
- dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
- if (!dev->p) {
- WARN_ON(1);
- return;
- }
- dev->p->device = dev;
dev->kobj.kset = devices_kset;
kobject_init(&dev->kobj, &device_ktype);
- klist_init(&dev->p->klist_children, klist_children_get,
+ klist_init(&dev->klist_children, klist_children_get,
klist_children_put);
INIT_LIST_HEAD(&dev->dma_pools);
init_MUTEX(&dev->sem);
@@ -932,8 +922,7 @@ int device_add(struct device *dev)
kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_attach_device(dev);
if (parent)
- klist_add_tail(&dev->p->knode_parent,
- &parent->p->klist_children);
+ klist_add_tail(&dev->knode_parent, &parent->klist_children);
if (dev->class) {
mutex_lock(&dev->class->p->class_mutex);
@@ -1047,7 +1036,7 @@ void device_del(struct device *dev)
device_pm_remove(dev);
dpm_sysfs_remove(dev);
if (parent)
- klist_del(&dev->p->knode_parent);
+ klist_del(&dev->knode_parent);
if (MAJOR(dev->devt)) {
device_remove_sys_dev_entry(dev);
device_remove_file(dev, &devt_attr);
@@ -1108,14 +1097,7 @@ void device_unregister(struct device *dev)
static struct device *next_device(struct klist_iter *i)
{
struct klist_node *n = klist_next(i);
- struct device *dev = NULL;
- struct device_private *p;
-
- if (n) {
- p = to_device_private_parent(n);
- dev = p->device;
- }
- return dev;
+ return n ? container_of(n, struct device, knode_parent) : NULL;
}
/**
@@ -1137,7 +1119,7 @@ int device_for_each_child(struct device *parent, void *data,
struct device *child;
int error = 0;
- klist_iter_init(&parent->p->klist_children, &i);
+ klist_iter_init(&parent->klist_children, &i);
while ((child = next_device(&i)) && !error)
error = fn(child, data);
klist_iter_exit(&i);
@@ -1168,7 +1150,7 @@ struct device *device_find_child(struct device *parent, void *data,
if (!parent)
return NULL;
- klist_iter_init(&parent->p->klist_children, &i);
+ klist_iter_init(&parent->klist_children, &i);
while ((child = next_device(&i)))
if (match(child, data) && get_device(child))
break;
@@ -1582,10 +1564,9 @@ int device_move(struct device *dev, struct device *new_parent)
old_parent = dev->parent;
dev->parent = new_parent;
if (old_parent)
- klist_remove(&dev->p->knode_parent);
+ klist_remove(&dev->knode_parent);
if (new_parent) {
- klist_add_tail(&dev->p->knode_parent,
- &new_parent->p->klist_children);
+ klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
set_dev_node(dev, dev_to_node(new_parent));
}
@@ -1597,11 +1578,11 @@ int device_move(struct device *dev, struct device *new_parent)
device_move_class_links(dev, new_parent, old_parent);
if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
if (new_parent)
- klist_remove(&dev->p->knode_parent);
+ klist_remove(&dev->knode_parent);
dev->parent = old_parent;
if (old_parent) {
- klist_add_tail(&dev->p->knode_parent,
- &old_parent->p->klist_children);
+ klist_add_tail(&dev->knode_parent,
+ &old_parent->klist_children);
set_dev_node(dev, dev_to_node(old_parent));
}
}
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 6fdaf76f033f..315bed8d5e7f 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -28,7 +28,7 @@
static void driver_bound(struct device *dev)
{
- if (klist_node_attached(&dev->p->knode_driver)) {
+ if (klist_node_attached(&dev->knode_driver)) {
printk(KERN_WARNING "%s: device %s already bound\n",
__func__, kobject_name(&dev->kobj));
return;
@@ -41,7 +41,7 @@ static void driver_bound(struct device *dev)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_BOUND_DRIVER, dev);
- klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
+ klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices);
}
static int driver_sysfs_add(struct device *dev)
@@ -310,7 +310,7 @@ static void __device_release_driver(struct device *dev)
drv->remove(dev);
devres_release_all(dev);
dev->driver = NULL;
- klist_remove(&dev->p->knode_driver);
+ klist_remove(&dev->knode_driver);
}
}
@@ -340,7 +340,6 @@ EXPORT_SYMBOL_GPL(device_release_driver);
*/
void driver_detach(struct device_driver *drv)
{
- struct device_private *dev_prv;
struct device *dev;
for (;;) {
@@ -349,10 +348,8 @@ void driver_detach(struct device_driver *drv)
spin_unlock(&drv->p->klist_devices.k_lock);
break;
}
- dev_prv = list_entry(drv->p->klist_devices.k_list.prev,
- struct device_private,
- knode_driver.n_node);
- dev = dev_prv->device;
+ dev = list_entry(drv->p->klist_devices.k_list.prev,
+ struct device, knode_driver.n_node);
get_device(dev);
spin_unlock(&drv->p->klist_devices.k_lock);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index b76cc69f1106..1e2bda780e48 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -19,14 +19,7 @@
static struct device *next_device(struct klist_iter *i)
{
struct klist_node *n = klist_next(i);
- struct device *dev = NULL;
- struct device_private *dev_prv;
-
- if (n) {
- dev_prv = to_device_private_driver(n);
- dev = dev_prv->device;
- }
- return dev;
+ return n ? container_of(n, struct device, knode_driver) : NULL;
}
/**
@@ -49,7 +42,7 @@ int driver_for_each_device(struct device_driver *drv, struct device *start,
return -EINVAL;
klist_iter_init_node(&drv->p->klist_devices, &i,
- start ? &start->p->knode_driver : NULL);
+ start ? &start->knode_driver : NULL);
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i);
@@ -83,7 +76,7 @@ struct device *driver_find_device(struct device_driver *drv,
return NULL;
klist_iter_init_node(&drv->p->klist_devices, &i,
- (start ? &start->p->knode_driver : NULL));
+ (start ? &start->knode_driver : NULL));
while ((dev = next_device(&i)))
if (match(dev, data) && get_device(dev))
break;
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index a8bc1cbcfa7c..a778fb52b11f 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -28,6 +28,7 @@
#include <linux/mm.h>
#include <linux/cpu.h>
#include <linux/module.h>
+#include <linux/hardirq.h>
#include <linux/topology.h>
#define define_one_ro(_name) \
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 4b1d4ac960f1..8df436ff7068 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -156,7 +156,7 @@ static volatile int fdc_busy = -1;
static volatile int fdc_nested;
static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
-static DECLARE_WAIT_QUEUE_HEAD(motor_wait);
+static DECLARE_COMPLETION(motor_on_completion);
static volatile int selected = -1; /* currently selected drive */
@@ -184,8 +184,7 @@ static unsigned char mfmencode[16]={
static unsigned char mfmdecode[128];
/* floppy internal millisecond timer stuff */
-static volatile int ms_busy = -1;
-static DECLARE_WAIT_QUEUE_HEAD(ms_wait);
+static DECLARE_COMPLETION(ms_wait_completion);
#define MS_TICKS ((amiga_eclock+50)/1000)
/*
@@ -211,8 +210,7 @@ static int fd_device[4] = { 0, 0, 0, 0 };
static irqreturn_t ms_isr(int irq, void *dummy)
{
- ms_busy = -1;
- wake_up(&ms_wait);
+ complete(&ms_wait_completion);
return IRQ_HANDLED;
}
@@ -220,19 +218,17 @@ static irqreturn_t ms_isr(int irq, void *dummy)
A more generic routine would do a schedule a la timer.device */
static void ms_delay(int ms)
{
- unsigned long flags;
int ticks;
+ static DEFINE_MUTEX(mutex);
+
if (ms > 0) {
- local_irq_save(flags);
- while (ms_busy == 0)
- sleep_on(&ms_wait);
- ms_busy = 0;
- local_irq_restore(flags);
+ mutex_lock(&mutex);
ticks = MS_TICKS*ms-1;
ciaa.tblo=ticks%256;
ciaa.tbhi=ticks/256;
ciaa.crb=0x19; /*count eclock, force load, one-shoot, start */
- sleep_on(&ms_wait);
+ wait_for_completion(&ms_wait_completion);
+ mutex_unlock(&mutex);
}
}
@@ -254,8 +250,7 @@ static void get_fdc(int drive)
printk("get_fdc: drive %d fdc_busy %d fdc_nested %d\n",drive,fdc_busy,fdc_nested);
#endif
local_irq_save(flags);
- while (!try_fdc(drive))
- sleep_on(&fdc_wait);
+ wait_event(fdc_wait, try_fdc(drive));
fdc_busy = drive;
fdc_nested++;
local_irq_restore(flags);
@@ -330,7 +325,7 @@ static void fd_deselect (int drive)
static void motor_on_callback(unsigned long nr)
{
if (!(ciaa.pra & DSKRDY) || --on_attempts == 0) {
- wake_up (&motor_wait);
+ complete_all(&motor_on_completion);
} else {
motor_on_timer.expires = jiffies + HZ/10;
add_timer(&motor_on_timer);
@@ -347,11 +342,12 @@ static int fd_motor_on(int nr)
unit[nr].motor = 1;
fd_select(nr);
+ INIT_COMPLETION(motor_on_completion);
motor_on_timer.data = nr;
mod_timer(&motor_on_timer, jiffies + HZ/2);
on_attempts = 10;
- sleep_on (&motor_wait);
+ wait_for_completion(&motor_on_completion);
fd_deselect(nr);
}
@@ -582,8 +578,7 @@ static void raw_read(int drive)
{
drive&=3;
get_fdc(drive);
- while (block_flag)
- sleep_on(&wait_fd_block);
+ wait_event(wait_fd_block, !block_flag);
fd_select(drive);
/* setup adkcon bits correctly */
custom.adkcon = ADK_MSBSYNC;
@@ -598,8 +593,7 @@ static void raw_read(int drive)
block_flag = 1;
- while (block_flag)
- sleep_on (&wait_fd_block);
+ wait_event(wait_fd_block, !block_flag);
custom.dsklen = 0;
fd_deselect(drive);
@@ -616,8 +610,7 @@ static int raw_write(int drive)
rel_fdc();
return 0;
}
- while (block_flag)
- sleep_on(&wait_fd_block);
+ wait_event(wait_fd_block, !block_flag);
fd_select(drive);
/* clear adkcon bits */
custom.adkcon = ADK_PRECOMP1|ADK_PRECOMP0|ADK_WORDSYNC|ADK_MSBSYNC;
@@ -1294,8 +1287,7 @@ static int non_int_flush_track (unsigned long nr)
writepending = 0;
return 0;
}
- while (block_flag == 2)
- sleep_on (&wait_fd_block);
+ wait_event(wait_fd_block, block_flag != 2);
}
else {
local_irq_restore(flags);
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 7bcc1d8bc967..34f80fa6fed1 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -406,6 +406,7 @@ static int nbd_do_it(struct nbd_device *lo)
ret = sysfs_create_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr);
if (ret) {
printk(KERN_ERR "nbd: sysfs_create_file failed!");
+ lo->pid = 0;
return ret;
}
@@ -413,6 +414,7 @@ static int nbd_do_it(struct nbd_device *lo)
nbd_end_request(req);
sysfs_remove_file(&disk_to_dev(lo->disk)->kobj, &pid_attr.attr);
+ lo->pid = 0;
return 0;
}
@@ -648,6 +650,8 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode,
set_capacity(lo->disk, lo->bytesize >> 9);
return 0;
case NBD_DO_IT:
+ if (lo->pid)
+ return -EBUSY;
if (!lo->file)
return -EINVAL;
thread = kthread_create(nbd_thread, lo, lo->disk->disk_name);
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
index 936466f62afd..bccc42bb9212 100644
--- a/drivers/block/ps3disk.c
+++ b/drivers/block/ps3disk.c
@@ -141,7 +141,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
start_sector = req->sector * priv->blocking_factor;
sectors = req->nr_sectors * priv->blocking_factor;
- dev_dbg(&dev->sbd.core, "%s:%u: %s %lu sectors starting at %lu\n",
+ dev_dbg(&dev->sbd.core, "%s:%u: %s %llu sectors starting at %llu\n",
__func__, __LINE__, op, sectors, start_sector);
if (write) {
@@ -178,7 +178,7 @@ static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
LV1_STORAGE_ATA_HDDOUT, 0, 0, 0,
0, &dev->tag);
if (res) {
- dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n",
+ dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n",
__func__, __LINE__, res);
end_request(req, 0);
return 0;
@@ -238,11 +238,11 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
if (tag != dev->tag)
dev_err(&dev->sbd.core,
- "%s:%u: tag mismatch, got %lx, expected %lx\n",
+ "%s:%u: tag mismatch, got %llx, expected %llx\n",
__func__, __LINE__, tag, dev->tag);
if (res) {
- dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+ dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n",
__func__, __LINE__, res, status);
return IRQ_HANDLED;
}
@@ -269,7 +269,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
op = read ? "read" : "write";
}
if (status) {
- dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+ dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
__LINE__, op, status);
error = -EIO;
} else {
@@ -297,7 +297,7 @@ static int ps3disk_sync_cache(struct ps3_storage_device *dev)
res = ps3stor_send_command(dev, LV1_STORAGE_ATA_HDDOUT, 0, 0, 0, 0);
if (res) {
- dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n",
+ dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n",
__func__, __LINE__, res);
return -EIO;
}
@@ -388,7 +388,7 @@ static int ps3disk_identify(struct ps3_storage_device *dev)
sizeof(ata_cmnd), ata_cmnd.buffer,
ata_cmnd.arglen);
if (res) {
- dev_err(&dev->sbd.core, "%s:%u: identify disk failed 0x%lx\n",
+ dev_err(&dev->sbd.core, "%s:%u: identify disk failed 0x%llx\n",
__func__, __LINE__, res);
return -EIO;
}
@@ -426,7 +426,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
if (dev->blk_size < 512) {
dev_err(&dev->sbd.core,
- "%s:%u: cannot handle block size %lu\n", __func__,
+ "%s:%u: cannot handle block size %llu\n", __func__,
__LINE__, dev->blk_size);
return -EINVAL;
}
@@ -512,7 +512,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
dev->regions[dev->region_idx].size*priv->blocking_factor);
dev_info(&dev->sbd.core,
- "%s is a %s (%lu MiB total, %lu MiB for OtherOS)\n",
+ "%s is a %s (%llu MiB total, %lu MiB for OtherOS)\n",
gendisk->disk_name, priv->model, priv->raw_capacity >> 11,
get_capacity(gendisk) >> 11);
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 953c0b83d758..5861e33efe63 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -153,7 +153,7 @@ static int vdc_send_attr(struct vio_driver_state *vio)
pkt.vdisk_block_size = port->vdisk_block_size;
pkt.max_xfer_size = port->max_xfer_size;
- viodbg(HS, "SEND ATTR xfer_mode[0x%x] blksz[%u] max_xfer[%lu]\n",
+ viodbg(HS, "SEND ATTR xfer_mode[0x%x] blksz[%u] max_xfer[%llu]\n",
pkt.xfer_mode, pkt.vdisk_block_size, pkt.max_xfer_size);
return vio_ldc_send(&port->vio, &pkt, sizeof(pkt));
@@ -164,8 +164,8 @@ static int vdc_handle_attr(struct vio_driver_state *vio, void *arg)
struct vdc_port *port = to_vdc_port(vio);
struct vio_disk_attr_info *pkt = arg;
- viodbg(HS, "GOT ATTR stype[0x%x] ops[%lx] disk_size[%lu] disk_type[%x] "
- "xfer_mode[0x%x] blksz[%u] max_xfer[%lu]\n",
+ viodbg(HS, "GOT ATTR stype[0x%x] ops[%llx] disk_size[%llu] disk_type[%x] "
+ "xfer_mode[0x%x] blksz[%u] max_xfer[%llu]\n",
pkt->tag.stype, pkt->operations,
pkt->vdisk_size, pkt->vdisk_type,
pkt->xfer_mode, pkt->vdisk_block_size,
@@ -753,7 +753,7 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
err = -ENODEV;
if ((vdev->dev_no << PARTITION_SHIFT) & ~(u64)MINORMASK) {
- printk(KERN_ERR PFX "Port id [%lu] too large.\n",
+ printk(KERN_ERR PFX "Port id [%llu] too large.\n",
vdev->dev_no);
goto err_out_release_mdesc;
}
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index 048d71d244d7..12fb816db7b0 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -1579,7 +1579,7 @@ static void ub_reset_task(struct work_struct *work)
struct ub_dev *sc = container_of(work, struct ub_dev, reset_work);
unsigned long flags;
struct ub_lun *lun;
- int lkr, rc;
+ int rc;
if (!sc->reset) {
printk(KERN_WARNING "%s: Running reset unrequested\n",
@@ -1597,10 +1597,11 @@ static void ub_reset_task(struct work_struct *work)
} else if (sc->dev->actconfig->desc.bNumInterfaces != 1) {
;
} else {
- if ((lkr = usb_lock_device_for_reset(sc->dev, sc->intf)) < 0) {
+ rc = usb_lock_device_for_reset(sc->dev, sc->intf);
+ if (rc < 0) {
printk(KERN_NOTICE
"%s: usb_lock_device_for_reset failed (%d)\n",
- sc->name, lkr);
+ sc->name, rc);
} else {
rc = usb_reset_device(sc->dev);
if (rc < 0) {
@@ -1608,9 +1609,7 @@ static void ub_reset_task(struct work_struct *work)
"usb_lock_device_for_reset failed (%d)\n",
sc->name, rc);
}
-
- if (lkr)
- usb_unlock_device(sc->dev);
+ usb_unlock_device(sc->dev);
}
}
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index 29e1dfafb7c6..381d686fc1a3 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -1206,6 +1206,7 @@ static struct of_device_id ace_of_match[] __devinitdata = {
{ .compatible = "xlnx,opb-sysace-1.00.b", },
{ .compatible = "xlnx,opb-sysace-1.00.c", },
{ .compatible = "xlnx,xps-sysace-1.00.a", },
+ { .compatible = "xlnx,sysace", },
{},
};
MODULE_DEVICE_TABLE(of, ace_of_match);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 35914b6e1d2a..f5be8081cd81 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -616,6 +616,7 @@ config HVC_ISERIES
default y
select HVC_DRIVER
select HVC_IRQ
+ select VIOPATH
help
iSeries machines support a hypervisor virtual console.
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 4e0cfdeab146..a58869ea8513 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -1963,6 +1963,7 @@ static int __init rs_init(void)
{
unsigned long flags;
struct serial_state * state;
+ int error;
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_SERIAL))
return -ENODEV;
@@ -1975,8 +1976,11 @@ static int __init rs_init(void)
* We request SERDAT and SERPER only, because the serial registers are
* too spreaded over the custom register space
*/
- if (!request_mem_region(CUSTOM_PHYSADDR+0x30, 4, "amiserial [Paula]"))
- return -EBUSY;
+ if (!request_mem_region(CUSTOM_PHYSADDR+0x30, 4,
+ "amiserial [Paula]")) {
+ error = -EBUSY;
+ goto fail_put_tty_driver;
+ }
IRQ_ports = NULL;
@@ -1997,8 +2001,9 @@ static int __init rs_init(void)
serial_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(serial_driver, &serial_ops);
- if (tty_register_driver(serial_driver))
- panic("Couldn't register serial driver\n");
+ error = tty_register_driver(serial_driver);
+ if (error)
+ goto fail_release_mem_region;
state = rs_table;
state->magic = SSTATE_MAGIC;
@@ -2024,8 +2029,14 @@ static int __init rs_init(void)
local_irq_save(flags);
/* set ISRs, and then disable the rx interrupts */
- request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state);
- request_irq(IRQ_AMIGA_RBF, ser_rx_int, IRQF_DISABLED, "serial RX", state);
+ error = request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state);
+ if (error)
+ goto fail_unregister;
+
+ error = request_irq(IRQ_AMIGA_RBF, ser_rx_int, IRQF_DISABLED,
+ "serial RX", state);
+ if (error)
+ goto fail_free_irq;
/* turn off Rx and Tx interrupts */
custom.intena = IF_RBF | IF_TBE;
@@ -2045,6 +2056,16 @@ static int __init rs_init(void)
ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */
return 0;
+
+fail_free_irq:
+ free_irq(IRQ_AMIGA_TBE, state);
+fail_unregister:
+ tty_unregister_driver(serial_driver);
+fail_release_mem_region:
+ release_mem_region(CUSTOM_PHYSADDR+0x30, 4);
+fail_put_tty_driver:
+ put_tty_driver(serial_driver);
+ return error;
}
static __exit void rs_exit(void)
@@ -2064,6 +2085,9 @@ static __exit void rs_exit(void)
kfree(info);
}
+ free_irq(IRQ_AMIGA_TBE, rs_table);
+ free_irq(IRQ_AMIGA_RBF, rs_table);
+
release_mem_region(CUSTOM_PHYSADDR+0x30, 4);
}
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c
index 977dfb1096a0..f6094ae0ef33 100644
--- a/drivers/char/bsr.c
+++ b/drivers/char/bsr.c
@@ -103,7 +103,7 @@ static ssize_t
bsr_len_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct bsr_dev *bsr_dev = dev_get_drvdata(dev);
- return sprintf(buf, "%lu\n", bsr_dev->bsr_len);
+ return sprintf(buf, "%llu\n", bsr_dev->bsr_len);
}
static struct device_attribute bsr_dev_attrs[] = {
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 39ad820b2350..af7c13ca9493 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -769,7 +769,7 @@ static int pc_open(struct tty_struct *tty, struct file *filp)
/* Check status of board configured in system. */
/*
- * I check to see if the epca_setup routine detected an user error. It
+ * I check to see if the epca_setup routine detected a user error. It
* might be better to put this in pc_init, but for the moment it goes
* here.
*/
diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c
index 91cdb35a9204..0afc8b82212e 100644
--- a/drivers/char/hvc_beat.c
+++ b/drivers/char/hvc_beat.c
@@ -44,7 +44,7 @@ static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt)
static unsigned char q[sizeof(unsigned long) * 2]
__attribute__((aligned(sizeof(unsigned long))));
static int qlen = 0;
- unsigned long got;
+ u64 got;
again:
if (qlen) {
@@ -63,7 +63,7 @@ again:
}
}
if (beat_get_term_char(vtermno, &got,
- ((unsigned long *)q), ((unsigned long *)q) + 1) == 0) {
+ ((u64 *)q), ((u64 *)q) + 1) == 0) {
qlen = got;
goto again;
}
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 5a8a4c28c867..94e7e3c8c05a 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -318,7 +318,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
} /* else count == 0 */
tty->driver_data = hp;
- tty->low_latency = 1; /* Makes flushes to ldisc synchronous. */
hp->tty = tty;
@@ -764,13 +763,11 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
return ERR_PTR(err);
}
- hp = kmalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size,
+ hp = kzalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size,
GFP_KERNEL);
if (!hp)
return ERR_PTR(-ENOMEM);
- memset(hp, 0x00, sizeof(*hp));
-
hp->vtermno = vtermno;
hp->data = data;
hp->ops = ops;
@@ -876,8 +873,11 @@ static int hvc_init(void)
goto stop_thread;
}
- /* FIXME: This mb() seems completely random. Remove it. */
- mb();
+ /*
+ * Make sure tty is fully registered before allowing it to be
+ * found by hvc_console_device.
+ */
+ smp_mb();
hvc_driver = drv;
return 0;
diff --git a/drivers/char/hvc_irq.c b/drivers/char/hvc_irq.c
index d09e5688d449..2623e177e8d6 100644
--- a/drivers/char/hvc_irq.c
+++ b/drivers/char/hvc_irq.c
@@ -37,7 +37,7 @@ int notifier_add_irq(struct hvc_struct *hp, int irq)
void notifier_del_irq(struct hvc_struct *hp, int irq)
{
- if (!irq)
+ if (!hp->irq_requested)
return;
free_irq(irq, hp);
hp->irq_requested = 0;
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c
index 5ea7d7713fca..a53496828b76 100644
--- a/drivers/char/hvc_iucv.c
+++ b/drivers/char/hvc_iucv.c
@@ -1,26 +1,30 @@
/*
- * hvc_iucv.c - z/VM IUCV back-end for the Hypervisor Console (HVC)
+ * hvc_iucv.c - z/VM IUCV hypervisor console (HVC) device driver
*
- * This back-end for HVC provides terminal access via
+ * This HVC device driver provides terminal access using
* z/VM IUCV communication paths.
*
- * Copyright IBM Corp. 2008.
+ * Copyright IBM Corp. 2008
*
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
*/
#define KMSG_COMPONENT "hvc_iucv"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/types.h>
#include <asm/ebcdic.h>
+#include <linux/delay.h>
+#include <linux/init.h>
#include <linux/mempool.h>
#include <linux/module.h>
#include <linux/tty.h>
+#include <linux/wait.h>
#include <net/iucv/iucv.h>
#include "hvc_console.h"
-/* HVC backend for z/VM IUCV */
+/* General device driver settings */
#define HVC_IUCV_MAGIC 0xc9e4c3e5
#define MAX_HVC_IUCV_LINES HVC_ALLOC_TTY_ADAPTERS
#define MEMPOOL_MIN_NR (PAGE_SIZE / sizeof(struct iucv_tty_buffer)/4)
@@ -33,14 +37,14 @@
#define MSG_TYPE_WINSIZE 0x08 /* Terminal window size update */
#define MSG_TYPE_DATA 0x10 /* Terminal data */
-#define MSG_SIZE(s) ((s) + offsetof(struct iucv_tty_msg, data))
struct iucv_tty_msg {
u8 version; /* Message version */
u8 type; /* Message type */
-#define MSG_MAX_DATALEN (~(u16)0)
+#define MSG_MAX_DATALEN ((u16)(~0))
u16 datalen; /* Payload length */
u8 data[]; /* Payload buffer */
} __attribute__((packed));
+#define MSG_SIZE(s) ((s) + offsetof(struct iucv_tty_msg, data))
enum iucv_state_t {
IUCV_DISCONN = 0,
@@ -54,19 +58,26 @@ enum tty_state_t {
};
struct hvc_iucv_private {
- struct hvc_struct *hvc; /* HVC console struct reference */
+ struct hvc_struct *hvc; /* HVC struct reference */
u8 srv_name[8]; /* IUCV service name (ebcdic) */
+ unsigned char is_console; /* Linux console usage flag */
enum iucv_state_t iucv_state; /* IUCV connection status */
enum tty_state_t tty_state; /* TTY status */
struct iucv_path *path; /* IUCV path pointer */
spinlock_t lock; /* hvc_iucv_private lock */
+#define SNDBUF_SIZE (PAGE_SIZE) /* must be < MSG_MAX_DATALEN */
+ void *sndbuf; /* send buffer */
+ size_t sndbuf_len; /* length of send buffer */
+#define QUEUE_SNDBUF_DELAY (HZ / 25)
+ struct delayed_work sndbuf_work; /* work: send iucv msg(s) */
+ wait_queue_head_t sndbuf_waitq; /* wait for send completion */
struct list_head tty_outqueue; /* outgoing IUCV messages */
struct list_head tty_inqueue; /* incoming IUCV messages */
};
struct iucv_tty_buffer {
struct list_head list; /* list pointer */
- struct iucv_message msg; /* store an incoming IUCV message */
+ struct iucv_message msg; /* store an IUCV message */
size_t offset; /* data buffer offset */
struct iucv_tty_msg *mbuf; /* buffer to store input/output data */
};
@@ -78,11 +89,12 @@ static void hvc_iucv_msg_pending(struct iucv_path *, struct iucv_message *);
static void hvc_iucv_msg_complete(struct iucv_path *, struct iucv_message *);
-/* Kernel module parameters */
-static unsigned long hvc_iucv_devices;
+/* Kernel module parameter: use one terminal device as default */
+static unsigned long hvc_iucv_devices = 1;
/* Array of allocated hvc iucv tty lines... */
static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES];
+#define IUCV_HVC_CON_IDX (0)
/* Kmem cache and mempool for iucv_tty_buffer elements */
static struct kmem_cache *hvc_iucv_buffer_cache;
@@ -112,7 +124,7 @@ struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num)
}
/**
- * alloc_tty_buffer() - Returns a new struct iucv_tty_buffer element.
+ * alloc_tty_buffer() - Return a new struct iucv_tty_buffer element.
* @size: Size of the internal buffer used to store data.
* @flags: Memory allocation flags passed to mempool.
*
@@ -120,7 +132,6 @@ struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num)
* allocates an internal data buffer with the specified size @size.
* Note: The total message size arises from the internal buffer size and the
* members of the iucv_tty_msg structure.
- *
* The function returns NULL if memory allocation has failed.
*/
static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags)
@@ -130,7 +141,7 @@ static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags)
bufp = mempool_alloc(hvc_iucv_mempool, flags);
if (!bufp)
return NULL;
- memset(bufp, 0, sizeof(struct iucv_tty_buffer));
+ memset(bufp, 0, sizeof(*bufp));
if (size > 0) {
bufp->msg.length = MSG_SIZE(size);
@@ -149,9 +160,6 @@ static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags)
/**
* destroy_tty_buffer() - destroy struct iucv_tty_buffer element.
* @bufp: Pointer to a struct iucv_tty_buffer element, SHALL NOT be NULL.
- *
- * The destroy_tty_buffer() function frees the internal data buffer and returns
- * the struct iucv_tty_buffer element back to the mempool for freeing.
*/
static void destroy_tty_buffer(struct iucv_tty_buffer *bufp)
{
@@ -161,11 +169,7 @@ static void destroy_tty_buffer(struct iucv_tty_buffer *bufp)
/**
* destroy_tty_buffer_list() - call destroy_tty_buffer() for each list element.
- * @list: List head pointer to a list containing struct iucv_tty_buffer
- * elements.
- *
- * Calls destroy_tty_buffer() for each struct iucv_tty_buffer element in the
- * list @list.
+ * @list: List containing struct iucv_tty_buffer elements.
*/
static void destroy_tty_buffer_list(struct list_head *list)
{
@@ -178,24 +182,24 @@ static void destroy_tty_buffer_list(struct list_head *list)
}
/**
- * hvc_iucv_write() - Receive IUCV message write data to HVC console buffer.
- * @priv: Pointer to hvc_iucv_private structure.
- * @buf: HVC console buffer for writing received terminal data.
- * @count: HVC console buffer size.
+ * hvc_iucv_write() - Receive IUCV message & write data to HVC buffer.
+ * @priv: Pointer to struct hvc_iucv_private
+ * @buf: HVC buffer for writing received terminal data.
+ * @count: HVC buffer size.
* @has_more_data: Pointer to an int variable.
*
* The function picks up pending messages from the input queue and receives
* the message data that is then written to the specified buffer @buf.
- * If the buffer size @count is less than the data message size, then the
+ * If the buffer size @count is less than the data message size, the
* message is kept on the input queue and @has_more_data is set to 1.
- * If the message data has been entirely written, the message is removed from
+ * If all message data has been written, the message is removed from
* the input queue.
*
* The function returns the number of bytes written to the terminal, zero if
* there are no pending data messages available or if there is no established
* IUCV path.
* If the IUCV path has been severed, then -EPIPE is returned to cause a
- * hang up (that is issued by the HVC console layer).
+ * hang up (that is issued by the HVC layer).
*/
static int hvc_iucv_write(struct hvc_iucv_private *priv,
char *buf, int count, int *has_more_data)
@@ -204,12 +208,12 @@ static int hvc_iucv_write(struct hvc_iucv_private *priv,
int written;
int rc;
- /* Immediately return if there is no IUCV connection */
+ /* immediately return if there is no IUCV connection */
if (priv->iucv_state == IUCV_DISCONN)
return 0;
- /* If the IUCV path has been severed, return -EPIPE to inform the
- * hvc console layer to hang up the tty device. */
+ /* if the IUCV path has been severed, return -EPIPE to inform the
+ * HVC layer to hang up the tty device. */
if (priv->iucv_state == IUCV_SEVERED)
return -EPIPE;
@@ -217,7 +221,7 @@ static int hvc_iucv_write(struct hvc_iucv_private *priv,
if (list_empty(&priv->tty_inqueue))
return 0;
- /* receive a iucv message and flip data to the tty (ldisc) */
+ /* receive an iucv message and flip data to the tty (ldisc) */
rb = list_first_entry(&priv->tty_inqueue, struct iucv_tty_buffer, list);
written = 0;
@@ -260,7 +264,7 @@ static int hvc_iucv_write(struct hvc_iucv_private *priv,
case MSG_TYPE_WINSIZE:
if (rb->mbuf->datalen != sizeof(struct winsize))
break;
- hvc_resize(priv->hvc, *((struct winsize *)rb->mbuf->data));
+ hvc_resize(priv->hvc, *((struct winsize *) rb->mbuf->data));
break;
case MSG_TYPE_ERROR: /* ignored ... */
@@ -284,10 +288,9 @@ out_written:
* @buf: Pointer to a buffer to store data
* @count: Size of buffer available for writing
*
- * The hvc_console thread calls this method to read characters from
- * the terminal backend. If an IUCV communication path has been established,
- * pending IUCV messages are received and data is copied into buffer @buf
- * up to @count bytes.
+ * The HVC thread calls this method to read characters from the back-end.
+ * If an IUCV communication path has been established, pending IUCV messages
+ * are received and data is copied into buffer @buf up to @count bytes.
*
* Locking: The routine gets called under an irqsave() spinlock; and
* the routine locks the struct hvc_iucv_private->lock to call
@@ -318,66 +321,122 @@ static int hvc_iucv_get_chars(uint32_t vtermno, char *buf, int count)
}
/**
- * hvc_iucv_send() - Send an IUCV message containing terminal data.
+ * hvc_iucv_queue() - Buffer terminal data for sending.
* @priv: Pointer to struct hvc_iucv_private instance.
* @buf: Buffer containing data to send.
- * @size: Size of buffer and amount of data to send.
+ * @count: Size of buffer and amount of data to send.
+ *
+ * The function queues data for sending. To actually send the buffered data,
+ * a work queue function is scheduled (with QUEUE_SNDBUF_DELAY).
+ * The function returns the number of data bytes that has been buffered.
*
- * If an IUCV communication path is established, the function copies the buffer
- * data to a newly allocated struct iucv_tty_buffer element, sends the data and
- * puts the element to the outqueue.
+ * If the device is not connected, data is ignored and the function returns
+ * @count.
+ * If the buffer is full, the function returns 0.
+ * If an existing IUCV communicaton path has been severed, -EPIPE is returned
+ * (that can be passed to HVC layer to cause a tty hangup).
+ */
+static int hvc_iucv_queue(struct hvc_iucv_private *priv, const char *buf,
+ int count)
+{
+ size_t len;
+
+ if (priv->iucv_state == IUCV_DISCONN)
+ return count; /* ignore data */
+
+ if (priv->iucv_state == IUCV_SEVERED)
+ return -EPIPE;
+
+ len = min_t(size_t, count, SNDBUF_SIZE - priv->sndbuf_len);
+ if (!len)
+ return 0;
+
+ memcpy(priv->sndbuf + priv->sndbuf_len, buf, len);
+ priv->sndbuf_len += len;
+
+ if (priv->iucv_state == IUCV_CONNECTED)
+ schedule_delayed_work(&priv->sndbuf_work, QUEUE_SNDBUF_DELAY);
+
+ return len;
+}
+
+/**
+ * hvc_iucv_send() - Send an IUCV message containing terminal data.
+ * @priv: Pointer to struct hvc_iucv_private instance.
*
- * If there is no IUCV communication path established, the function returns 0.
- * If an existing IUCV communicaton path has been severed, the function returns
- * -EPIPE (can be passed to HVC layer to cause a tty hangup).
+ * If an IUCV communication path has been established, the buffered output data
+ * is sent via an IUCV message and the number of bytes sent is returned.
+ * Returns 0 if there is no established IUCV communication path or
+ * -EPIPE if an existing IUCV communicaton path has been severed.
*/
-static int hvc_iucv_send(struct hvc_iucv_private *priv, const char *buf,
- int count)
+static int hvc_iucv_send(struct hvc_iucv_private *priv)
{
struct iucv_tty_buffer *sb;
- int rc;
- u16 len;
+ int rc, len;
if (priv->iucv_state == IUCV_SEVERED)
return -EPIPE;
if (priv->iucv_state == IUCV_DISCONN)
- return 0;
+ return -EIO;
- len = min_t(u16, MSG_MAX_DATALEN, count);
+ if (!priv->sndbuf_len)
+ return 0;
/* allocate internal buffer to store msg data and also compute total
* message length */
- sb = alloc_tty_buffer(len, GFP_ATOMIC);
+ sb = alloc_tty_buffer(priv->sndbuf_len, GFP_ATOMIC);
if (!sb)
return -ENOMEM;
- sb->mbuf->datalen = len;
- memcpy(sb->mbuf->data, buf, len);
+ memcpy(sb->mbuf->data, priv->sndbuf, priv->sndbuf_len);
+ sb->mbuf->datalen = (u16) priv->sndbuf_len;
+ sb->msg.length = MSG_SIZE(sb->mbuf->datalen);
list_add_tail(&sb->list, &priv->tty_outqueue);
rc = __iucv_message_send(priv->path, &sb->msg, 0, 0,
(void *) sb->mbuf, sb->msg.length);
if (rc) {
+ /* drop the message here; however we might want to handle
+ * 0x03 (msg limit reached) by trying again... */
list_del(&sb->list);
destroy_tty_buffer(sb);
- len = 0;
}
+ len = priv->sndbuf_len;
+ priv->sndbuf_len = 0;
return len;
}
/**
+ * hvc_iucv_sndbuf_work() - Send buffered data over IUCV
+ * @work: Work structure.
+ *
+ * This work queue function sends buffered output data over IUCV and,
+ * if not all buffered data could be sent, reschedules itself.
+ */
+static void hvc_iucv_sndbuf_work(struct work_struct *work)
+{
+ struct hvc_iucv_private *priv;
+
+ priv = container_of(work, struct hvc_iucv_private, sndbuf_work.work);
+ if (!priv)
+ return;
+
+ spin_lock_bh(&priv->lock);
+ hvc_iucv_send(priv);
+ spin_unlock_bh(&priv->lock);
+}
+
+/**
* hvc_iucv_put_chars() - HVC put_chars operation.
* @vtermno: HVC virtual terminal number.
* @buf: Pointer to an buffer to read data from
* @count: Size of buffer available for reading
*
- * The hvc_console thread calls this method to write characters from
- * to the terminal backend.
- * The function calls hvc_iucv_send() under the lock of the
- * struct hvc_iucv_private instance that corresponds to the tty @vtermno.
+ * The HVC thread calls this method to write characters to the back-end.
+ * The function calls hvc_iucv_queue() to queue terminal data for sending.
*
* Locking: The method gets called under an irqsave() spinlock; and
* locks struct hvc_iucv_private->lock.
@@ -385,7 +444,7 @@ static int hvc_iucv_send(struct hvc_iucv_private *priv, const char *buf,
static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count)
{
struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno);
- int sent;
+ int queued;
if (count <= 0)
return 0;
@@ -394,10 +453,10 @@ static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count)
return -ENODEV;
spin_lock(&priv->lock);
- sent = hvc_iucv_send(priv, buf, count);
+ queued = hvc_iucv_queue(priv, buf, count);
spin_unlock(&priv->lock);
- return sent;
+ return queued;
}
/**
@@ -406,7 +465,7 @@ static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count)
* @id: Additional data (originally passed to hvc_alloc): the index of an struct
* hvc_iucv_private instance.
*
- * The function sets the tty state to TTY_OPEN for the struct hvc_iucv_private
+ * The function sets the tty state to TTY_OPENED for the struct hvc_iucv_private
* instance that is derived from @id. Always returns 0.
*
* Locking: struct hvc_iucv_private->lock, spin_lock_bh
@@ -427,12 +486,8 @@ static int hvc_iucv_notifier_add(struct hvc_struct *hp, int id)
}
/**
- * hvc_iucv_cleanup() - Clean up function if the tty portion is finally closed.
+ * hvc_iucv_cleanup() - Clean up and reset a z/VM IUCV HVC instance.
* @priv: Pointer to the struct hvc_iucv_private instance.
- *
- * The functions severs the established IUCV communication path (if any), and
- * destroy struct iucv_tty_buffer elements from the in- and outqueue. Finally,
- * the functions resets the states to TTY_CLOSED and IUCV_DISCONN.
*/
static void hvc_iucv_cleanup(struct hvc_iucv_private *priv)
{
@@ -441,25 +496,62 @@ static void hvc_iucv_cleanup(struct hvc_iucv_private *priv)
priv->tty_state = TTY_CLOSED;
priv->iucv_state = IUCV_DISCONN;
+
+ priv->sndbuf_len = 0;
}
/**
- * hvc_iucv_notifier_hangup() - HVC notifier for tty hangups.
- * @hp: Pointer to the HVC device (struct hvc_struct)
- * @id: Additional data (originally passed to hvc_alloc): the index of an struct
- * hvc_iucv_private instance.
+ * tty_outqueue_empty() - Test if the tty outq is empty
+ * @priv: Pointer to struct hvc_iucv_private instance.
+ */
+static inline int tty_outqueue_empty(struct hvc_iucv_private *priv)
+{
+ int rc;
+
+ spin_lock_bh(&priv->lock);
+ rc = list_empty(&priv->tty_outqueue);
+ spin_unlock_bh(&priv->lock);
+
+ return rc;
+}
+
+/**
+ * flush_sndbuf_sync() - Flush send buffer and wait for completion
+ * @priv: Pointer to struct hvc_iucv_private instance.
*
- * This routine notifies the HVC backend that a tty hangup (carrier loss,
- * virtual or otherwise) has occured.
+ * The routine cancels a pending sndbuf work, calls hvc_iucv_send()
+ * to flush any buffered terminal output data and waits for completion.
+ */
+static void flush_sndbuf_sync(struct hvc_iucv_private *priv)
+{
+ int sync_wait;
+
+ cancel_delayed_work_sync(&priv->sndbuf_work);
+
+ spin_lock_bh(&priv->lock);
+ hvc_iucv_send(priv); /* force sending buffered data */
+ sync_wait = !list_empty(&priv->tty_outqueue); /* anything queued ? */
+ spin_unlock_bh(&priv->lock);
+
+ if (sync_wait)
+ wait_event_timeout(priv->sndbuf_waitq,
+ tty_outqueue_empty(priv), HZ);
+}
+
+/**
+ * hvc_iucv_notifier_hangup() - HVC notifier for TTY hangups.
+ * @hp: Pointer to the HVC device (struct hvc_struct)
+ * @id: Additional data (originally passed to hvc_alloc):
+ * the index of an struct hvc_iucv_private instance.
*
- * The HVC backend for z/VM IUCV ignores virtual hangups (vhangup()), to keep
- * an existing IUCV communication path established.
+ * This routine notifies the HVC back-end that a tty hangup (carrier loss,
+ * virtual or otherwise) has occured.
+ * The z/VM IUCV HVC device driver ignores virtual hangups (vhangup())
+ * to keep an existing IUCV communication path established.
* (Background: vhangup() is called from user space (by getty or login) to
* disable writing to the tty by other applications).
- *
- * If the tty has been opened (e.g. getty) and an established IUCV path has been
- * severed (we caused the tty hangup in that case), then the functions invokes
- * hvc_iucv_cleanup() to clean up.
+ * If the tty has been opened and an established IUCV path has been severed
+ * (we caused the tty hangup), the function calls hvc_iucv_cleanup().
*
* Locking: struct hvc_iucv_private->lock
*/
@@ -471,12 +563,12 @@ static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id)
if (!priv)
return;
+ flush_sndbuf_sync(priv);
+
spin_lock_bh(&priv->lock);
/* NOTE: If the hangup was scheduled by ourself (from the iucv
- * path_servered callback [IUCV_SEVERED]), then we have to
- * finally clean up the tty backend structure and set state to
- * TTY_CLOSED.
- *
+ * path_servered callback [IUCV_SEVERED]), we have to clean up
+ * our structure and to set state to TTY_CLOSED.
* If the tty was hung up otherwise (e.g. vhangup()), then we
* ignore this hangup and keep an established IUCV path open...
* (...the reason is that we are not able to connect back to the
@@ -494,10 +586,9 @@ static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id)
* @id: Additional data (originally passed to hvc_alloc):
* the index of an struct hvc_iucv_private instance.
*
- * This routine notifies the HVC backend that the last tty device file
- * descriptor has been closed.
- * The function calls hvc_iucv_cleanup() to clean up the struct hvc_iucv_private
- * instance.
+ * This routine notifies the HVC back-end that the last tty device fd has been
+ * closed. The function calls hvc_iucv_cleanup() to clean up the struct
+ * hvc_iucv_private instance.
*
* Locking: struct hvc_iucv_private->lock
*/
@@ -510,6 +601,8 @@ static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)
if (!priv)
return;
+ flush_sndbuf_sync(priv);
+
spin_lock_bh(&priv->lock);
path = priv->path; /* save reference to IUCV path */
priv->path = NULL;
@@ -527,20 +620,18 @@ static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)
/**
* hvc_iucv_path_pending() - IUCV handler to process a connection request.
* @path: Pending path (struct iucv_path)
- * @ipvmid: Originator z/VM system identifier
+ * @ipvmid: z/VM system identifier of originator
* @ipuser: User specified data for this path
* (AF_IUCV: port/service name and originator port)
*
- * The function uses the @ipuser data to check to determine if the pending
- * path belongs to a terminal managed by this HVC backend.
- * If the check is successful, then an additional check is done to ensure
- * that a terminal cannot be accessed multiple times (only one connection
- * to a terminal is allowed). In that particular case, the pending path is
- * severed. If it is the first connection, the pending path is accepted and
- * associated to the struct hvc_iucv_private. The iucv state is updated to
- * reflect that a communication path has been established.
+ * The function uses the @ipuser data to determine if the pending path belongs
+ * to a terminal managed by this device driver.
+ * If the path belongs to this driver, ensure that the terminal is not accessed
+ * multiple times (only one connection to a terminal is allowed).
+ * If the terminal is not yet connected, the pending path is accepted and is
+ * associated to the appropriate struct hvc_iucv_private instance.
*
- * Returns 0 if the path belongs to a terminal managed by the this HVC backend;
+ * Returns 0 if @path belongs to a terminal managed by the this device driver;
* otherwise returns -ENODEV in order to dispatch this path to other handlers.
*
* Locking: struct hvc_iucv_private->lock
@@ -559,7 +650,6 @@ static int hvc_iucv_path_pending(struct iucv_path *path,
priv = hvc_iucv_table[i];
break;
}
-
if (!priv)
return -ENODEV;
@@ -588,6 +678,9 @@ static int hvc_iucv_path_pending(struct iucv_path *path,
priv->path = path;
priv->iucv_state = IUCV_CONNECTED;
+ /* flush buffered output data... */
+ schedule_delayed_work(&priv->sndbuf_work, 5);
+
out_path_handled:
spin_unlock(&priv->lock);
return 0;
@@ -603,8 +696,7 @@ out_path_handled:
* sets the iucv state to IUCV_SEVERED for the associated struct
* hvc_iucv_private instance. Later, the IUCV_SEVERED state triggers a tty
* hangup (hvc_iucv_get_chars() / hvc_iucv_write()).
- *
- * If tty portion of the HVC is closed then clean up the outqueue in addition.
+ * If tty portion of the HVC is closed, clean up the outqueue.
*
* Locking: struct hvc_iucv_private->lock
*/
@@ -615,15 +707,25 @@ static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
spin_lock(&priv->lock);
priv->iucv_state = IUCV_SEVERED;
- /* NOTE: If the tty has not yet been opened by a getty program
- * (e.g. to see console messages), then cleanup the
- * hvc_iucv_private structure to allow re-connects.
+ /* If the tty has not yet been opened, clean up the hvc_iucv_private
+ * structure to allow re-connects.
+ * This is also done for our console device because console hangups
+ * are handled specially and no notifier is called by HVC.
+ * The tty session is active (TTY_OPEN) and ready for re-connects...
*
- * If the tty has been opened, the get_chars() callback returns
- * -EPIPE to signal the hvc console layer to hang up the tty. */
+ * If it has been opened, let get_chars() return -EPIPE to signal the
+ * HVC layer to hang up the tty.
+ * If so, we need to wake up the HVC thread to call get_chars()...
+ */
priv->path = NULL;
if (priv->tty_state == TTY_CLOSED)
hvc_iucv_cleanup(priv);
+ else
+ if (priv->is_console) {
+ hvc_iucv_cleanup(priv);
+ priv->tty_state = TTY_OPENED;
+ } else
+ hvc_kick();
spin_unlock(&priv->lock);
/* finally sever path (outside of priv->lock due to lock ordering) */
@@ -636,9 +738,9 @@ static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
* @path: Pending path (struct iucv_path)
* @msg: Pointer to the IUCV message
*
- * The function stores an incoming message on the input queue for later
+ * The function puts an incoming message on the input queue for later
* processing (by hvc_iucv_get_chars() / hvc_iucv_write()).
- * However, if the tty has not yet been opened, the message is rejected.
+ * If the tty has not yet been opened, the message is rejected.
*
* Locking: struct hvc_iucv_private->lock
*/
@@ -648,6 +750,12 @@ static void hvc_iucv_msg_pending(struct iucv_path *path,
struct hvc_iucv_private *priv = path->private;
struct iucv_tty_buffer *rb;
+ /* reject messages that exceed max size of iucv_tty_msg->datalen */
+ if (msg->length > MSG_SIZE(MSG_MAX_DATALEN)) {
+ iucv_message_reject(path, msg);
+ return;
+ }
+
spin_lock(&priv->lock);
/* reject messages if tty has not yet been opened */
@@ -656,7 +764,7 @@ static void hvc_iucv_msg_pending(struct iucv_path *path,
goto unlock_return;
}
- /* allocate buffer an empty buffer element */
+ /* allocate tty buffer to save iucv msg only */
rb = alloc_tty_buffer(0, GFP_ATOMIC);
if (!rb) {
iucv_message_reject(path, msg);
@@ -666,7 +774,7 @@ static void hvc_iucv_msg_pending(struct iucv_path *path,
list_add_tail(&rb->list, &priv->tty_inqueue);
- hvc_kick(); /* wakup hvc console thread */
+ hvc_kick(); /* wake up hvc thread */
unlock_return:
spin_unlock(&priv->lock);
@@ -677,10 +785,10 @@ unlock_return:
* @path: Pending path (struct iucv_path)
* @msg: Pointer to the IUCV message
*
- * The function is called upon completion of message delivery and the
- * message is removed from the outqueue. Additional delivery information
- * can be found in msg->audit: rejected messages (0x040000 (IPADRJCT)) and
- * purged messages (0x010000 (IPADPGNR)).
+ * The function is called upon completion of message delivery to remove the
+ * message from the outqueue. Additional delivery information can be found
+ * msg->audit: rejected messages (0x040000 (IPADRJCT)), and
+ * purged messages (0x010000 (IPADPGNR)).
*
* Locking: struct hvc_iucv_private->lock
*/
@@ -697,6 +805,7 @@ static void hvc_iucv_msg_complete(struct iucv_path *path,
list_move(&ent->list, &list_remove);
break;
}
+ wake_up(&priv->sndbuf_waitq);
spin_unlock(&priv->lock);
destroy_tty_buffer_list(&list_remove);
}
@@ -713,13 +822,14 @@ static struct hv_ops hvc_iucv_ops = {
/**
* hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance
- * @id: hvc_iucv_table index
+ * @id: hvc_iucv_table index
+ * @is_console: Flag if the instance is used as Linux console
*
- * This function allocates a new hvc_iucv_private struct and put the
- * instance into hvc_iucv_table at index @id.
+ * This function allocates a new hvc_iucv_private structure and stores
+ * the instance in hvc_iucv_table at index @id.
* Returns 0 on success; otherwise non-zero.
*/
-static int __init hvc_iucv_alloc(int id)
+static int __init hvc_iucv_alloc(int id, unsigned int is_console)
{
struct hvc_iucv_private *priv;
char name[9];
@@ -732,18 +842,33 @@ static int __init hvc_iucv_alloc(int id)
spin_lock_init(&priv->lock);
INIT_LIST_HEAD(&priv->tty_outqueue);
INIT_LIST_HEAD(&priv->tty_inqueue);
+ INIT_DELAYED_WORK(&priv->sndbuf_work, hvc_iucv_sndbuf_work);
+ init_waitqueue_head(&priv->sndbuf_waitq);
+
+ priv->sndbuf = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!priv->sndbuf) {
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ /* set console flag */
+ priv->is_console = is_console;
- /* Finally allocate hvc */
- priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id,
- HVC_IUCV_MAGIC + id, &hvc_iucv_ops, PAGE_SIZE);
+ /* finally allocate hvc */
+ priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */
+ HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256);
if (IS_ERR(priv->hvc)) {
rc = PTR_ERR(priv->hvc);
+ free_page((unsigned long) priv->sndbuf);
kfree(priv);
return rc;
}
+ /* notify HVC thread instead of using polling */
+ priv->hvc->irq_requested = 1;
+
/* setup iucv related information */
- snprintf(name, 9, "ihvc%-4d", id);
+ snprintf(name, 9, "lnxhvc%-2d", id);
memcpy(priv->srv_name, name, 8);
ASCEBC(priv->srv_name, 8);
@@ -752,15 +877,16 @@ static int __init hvc_iucv_alloc(int id)
}
/**
- * hvc_iucv_init() - Initialization of HVC backend for z/VM IUCV
+ * hvc_iucv_init() - z/VM IUCV HVC device driver initialization
*/
static int __init hvc_iucv_init(void)
{
- int rc, i;
+ int rc;
+ unsigned int i;
if (!MACHINE_IS_VM) {
- pr_warning("The z/VM IUCV Hypervisor console cannot be "
- "used without z/VM.\n");
+ pr_info("The z/VM IUCV HVC device driver cannot "
+ "be used without z/VM\n");
return -ENODEV;
}
@@ -774,26 +900,33 @@ static int __init hvc_iucv_init(void)
sizeof(struct iucv_tty_buffer),
0, 0, NULL);
if (!hvc_iucv_buffer_cache) {
- pr_err("Not enough memory for driver initialization "
- "(rs=%d).\n", 1);
+ pr_err("Allocating memory failed with reason code=%d\n", 1);
return -ENOMEM;
}
hvc_iucv_mempool = mempool_create_slab_pool(MEMPOOL_MIN_NR,
hvc_iucv_buffer_cache);
if (!hvc_iucv_mempool) {
- pr_err("Not enough memory for driver initialization "
- "(rs=%d).\n", 2);
+ pr_err("Allocating memory failed with reason code=%d\n", 2);
kmem_cache_destroy(hvc_iucv_buffer_cache);
return -ENOMEM;
}
+ /* register the first terminal device as console
+ * (must be done before allocating hvc terminal devices) */
+ rc = hvc_instantiate(HVC_IUCV_MAGIC, IUCV_HVC_CON_IDX, &hvc_iucv_ops);
+ if (rc) {
+ pr_err("Registering HVC terminal device as "
+ "Linux console failed\n");
+ goto out_error_memory;
+ }
+
/* allocate hvc_iucv_private structs */
for (i = 0; i < hvc_iucv_devices; i++) {
- rc = hvc_iucv_alloc(i);
+ rc = hvc_iucv_alloc(i, (i == IUCV_HVC_CON_IDX) ? 1 : 0);
if (rc) {
- pr_err("Could not create new z/VM IUCV HVC backend "
- "rc=%d.\n", rc);
+ pr_err("Creating a new HVC terminal device "
+ "failed with error code=%d\n", rc);
goto out_error_hvc;
}
}
@@ -801,7 +934,8 @@ static int __init hvc_iucv_init(void)
/* register IUCV callback handler */
rc = iucv_register(&hvc_iucv_handler, 0);
if (rc) {
- pr_err("Could not register iucv handler (rc=%d).\n", rc);
+ pr_err("Registering IUCV handlers failed with error code=%d\n",
+ rc);
goto out_error_iucv;
}
@@ -816,22 +950,13 @@ out_error_hvc:
hvc_remove(hvc_iucv_table[i]->hvc);
kfree(hvc_iucv_table[i]);
}
+out_error_memory:
mempool_destroy(hvc_iucv_mempool);
kmem_cache_destroy(hvc_iucv_buffer_cache);
return rc;
}
/**
- * hvc_iucv_console_init() - Early console initialization
- */
-static int __init hvc_iucv_console_init(void)
-{
- if (!MACHINE_IS_VM || !hvc_iucv_devices)
- return -ENODEV;
- return hvc_instantiate(HVC_IUCV_MAGIC, 0, &hvc_iucv_ops);
-}
-
-/**
* hvc_iucv_config() - Parsing of hvc_iucv= kernel command line parameter
* @val: Parameter value (numeric)
*/
@@ -841,10 +966,5 @@ static int __init hvc_iucv_config(char *val)
}
-module_init(hvc_iucv_init);
-console_initcall(hvc_iucv_console_init);
+device_initcall(hvc_iucv_init);
__setup("hvc_iucv=", hvc_iucv_config);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("HVC back-end for z/VM IUCV.");
-MODULE_AUTHOR("Hendrik Brueckner <brueckner@linux.vnet.ibm.com>");
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
index 8859aeac2d25..9b3e09cd41f9 100644
--- a/drivers/char/hw_random/n2-drv.c
+++ b/drivers/char/hw_random/n2-drv.c
@@ -482,7 +482,7 @@ static void n2rng_dump_test_buffer(struct n2rng *np)
int i;
for (i = 0; i < SELFTEST_BUFFER_WORDS; i++)
- dev_err(&np->op->dev, "Test buffer slot %d [0x%016lx]\n",
+ dev_err(&np->op->dev, "Test buffer slot %d [0x%016llx]\n",
i, np->test_buffer[i]);
}
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c
index 79b6f461be75..afbe45676d71 100644
--- a/drivers/char/ps3flash.c
+++ b/drivers/char/ps3flash.c
@@ -44,7 +44,7 @@ static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev,
u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors,
write);
if (res) {
- dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+ dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
__LINE__, write ? "write" : "read", res);
return -EIO;
}
@@ -59,7 +59,7 @@ static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev,
max_sectors = dev->bounce_size / dev->blk_size;
if (sectors > max_sectors) {
- dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %lu\n",
+ dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %llu\n",
__func__, __LINE__, max_sectors);
sectors = max_sectors;
}
@@ -144,7 +144,7 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
goto fail;
}
- n = min(remaining, sectors_read*dev->blk_size-offset);
+ n = min_t(u64, remaining, sectors_read*dev->blk_size-offset);
dev_dbg(&dev->sbd.core,
"%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",
__func__, __LINE__, n, dev->bounce_buf+offset, buf);
@@ -225,7 +225,7 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
if (end_read_sector >= start_read_sector) {
/* Merge head and tail */
dev_dbg(&dev->sbd.core,
- "Merged head and tail: %lu sectors at %lu\n",
+ "Merged head and tail: %llu sectors at %llu\n",
chunk_sectors, start_write_sector);
res = ps3flash_read_sectors(dev, start_write_sector,
chunk_sectors, 0);
@@ -235,7 +235,7 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
if (head) {
/* Read head */
dev_dbg(&dev->sbd.core,
- "head: %lu sectors at %lu\n", head,
+ "head: %llu sectors at %llu\n", head,
start_write_sector);
res = ps3flash_read_sectors(dev,
start_write_sector,
@@ -247,7 +247,7 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
start_write_sector+chunk_sectors) {
/* Read tail */
dev_dbg(&dev->sbd.core,
- "tail: %lu sectors at %lu\n", tail,
+ "tail: %llu sectors at %llu\n", tail,
start_read_sector);
sec_off = start_read_sector-start_write_sector;
res = ps3flash_read_sectors(dev,
@@ -258,7 +258,7 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
}
}
- n = min(remaining, dev->bounce_size-offset);
+ n = min_t(u64, remaining, dev->bounce_size-offset);
dev_dbg(&dev->sbd.core,
"%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",
__func__, __LINE__, n, buf, dev->bounce_buf+offset);
@@ -299,11 +299,11 @@ static irqreturn_t ps3flash_interrupt(int irq, void *data)
if (tag != dev->tag)
dev_err(&dev->sbd.core,
- "%s:%u: tag mismatch, got %lx, expected %lx\n",
+ "%s:%u: tag mismatch, got %llx, expected %llx\n",
__func__, __LINE__, tag, dev->tag);
if (res) {
- dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+ dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n",
__func__, __LINE__, res, status);
} else {
dev->lv1_status = status;
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 112a6ba9a96f..31038a0052a2 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -32,7 +32,7 @@
/* These are global because they are accessed in tty_io.c */
#ifdef CONFIG_UNIX98_PTYS
-struct tty_driver *ptm_driver;
+static struct tty_driver *ptm_driver;
static struct tty_driver *pts_driver;
#endif
@@ -230,9 +230,7 @@ static void pty_set_termios(struct tty_struct *tty,
/**
* pty_do_resize - resize event
* @tty: tty being resized
- * @real_tty: real tty (not the same as tty if using a pty/tty pair)
- * @rows: rows (character)
- * @cols: cols (character)
+ * @ws: window size being set.
*
* Update the termios variables and send the neccessary signals to
* peform a terminal resize correctly
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 20d6efb6324e..e0d0f8b2696b 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -48,9 +48,10 @@
* CONFIG_HPET_EMULATE_RTC
* 1.12a Maciej W. Rozycki: Handle memory-mapped chips properly.
* 1.12ac Alan Cox: Allow read access to the day of week register
+ * 1.12b David John: Remove calls to the BKL.
*/
-#define RTC_VERSION "1.12ac"
+#define RTC_VERSION "1.12b"
/*
* Note that *all* calls to CMOS_READ and CMOS_WRITE are done with
@@ -73,7 +74,6 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/sysctl.h>
#include <linux/wait.h>
#include <linux/bcd.h>
@@ -182,8 +182,8 @@ static int rtc_proc_open(struct inode *inode, struct file *file);
/*
* rtc_status is never changed by rtc_interrupt, and ioctl/open/close is
- * protected by the big kernel lock. However, ioctl can still disable the timer
- * in rtc_status and then with del_timer after the interrupt has read
+ * protected by the spin lock rtc_lock. However, ioctl can still disable the
+ * timer in rtc_status and then with del_timer after the interrupt has read
* 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)
*/
@@ -720,9 +720,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret;
- lock_kernel();
ret = rtc_do_ioctl(cmd, arg, 0);
- unlock_kernel();
return ret;
}
@@ -731,12 +729,8 @@ static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
* Also clear the previous interrupt data on an open, and clean
* up things on a close.
*/
-
-/* We use rtc_lock to protect against concurrent opens. So the BKL is not
- * needed here. Or anywhere else in this driver. */
static int rtc_open(struct inode *inode, struct file *file)
{
- lock_kernel();
spin_lock_irq(&rtc_lock);
if (rtc_status & RTC_IS_OPEN)
@@ -746,12 +740,10 @@ static int rtc_open(struct inode *inode, struct file *file)
rtc_irq_data = 0;
spin_unlock_irq(&rtc_lock);
- unlock_kernel();
return 0;
out_busy:
spin_unlock_irq(&rtc_lock);
- unlock_kernel();
return -EBUSY;
}
@@ -800,7 +792,6 @@ no_irq:
}
#ifdef RTC_IRQ
-/* Called without the kernel lock - fine */
static unsigned int rtc_poll(struct file *file, poll_table *wait)
{
unsigned long l;
diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
index 33872a219df6..33a2b531802e 100644
--- a/drivers/char/ser_a2232.c
+++ b/drivers/char/ser_a2232.c
@@ -718,6 +718,7 @@ static int __init a2232board_init(void)
u_char *from;
volatile u_char *to;
volatile struct a2232memory *mem;
+ int error, i;
#ifdef CONFIG_SMP
return -ENODEV; /* This driver is not SMP aware. Is there an SMP ZorroII-bus-machine? */
@@ -797,8 +798,15 @@ static int __init a2232board_init(void)
*/
if (a2232_init_drivers()) return -ENODEV; // maybe we should use a different -Exxx?
- request_irq(IRQ_AMIGA_VERTB, a2232_vbl_inter, 0, "A2232 serial VBL", a2232_driver_ID);
- return 0;
+ error = request_irq(IRQ_AMIGA_VERTB, a2232_vbl_inter, 0,
+ "A2232 serial VBL", a2232_driver_ID);
+ if (error) {
+ for (i = 0; i < nr_a2232; i++)
+ zorro_release_device(zd_a2232[i]);
+ tty_unregister_driver(a2232_driver);
+ put_tty_driver(a2232_driver);
+ }
+ return error;
}
static void __exit a2232board_exit(void)
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 53544e21f191..f329f459817c 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -1,6 +1,4 @@
/*
- * $Id: synclink_gt.c,v 4.50 2007/07/25 19:29:25 paulkf Exp $
- *
* Device driver for Microgate SyncLink GT serial adapters.
*
* written by Paul Fulghum for Microgate Corporation
@@ -91,7 +89,6 @@
* module identification
*/
static char *driver_name = "SyncLink GT";
-static char *driver_version = "$Revision: 4.50 $";
static char *tty_driver_name = "synclink_gt";
static char *tty_dev_prefix = "ttySLG";
MODULE_LICENSE("GPL");
@@ -1309,7 +1306,7 @@ static int read_proc(char *page, char **start, off_t off, int count,
off_t begin = 0;
struct slgt_info *info;
- len += sprintf(page, "synclink_gt driver:%s\n", driver_version);
+ len += sprintf(page, "synclink_gt driver\n");
info = slgt_device_list;
while( info ) {
@@ -2441,7 +2438,7 @@ static void program_hw(struct slgt_info *info)
info->ri_chkcount = 0;
info->dsr_chkcount = 0;
- slgt_irq_on(info, IRQ_DCD | IRQ_CTS | IRQ_DSR);
+ slgt_irq_on(info, IRQ_DCD | IRQ_CTS | IRQ_DSR | IRQ_RI);
get_signals(info);
if (info->netcount ||
@@ -3576,7 +3573,7 @@ static void slgt_cleanup(void)
struct slgt_info *info;
struct slgt_info *tmp;
- printk("unload %s %s\n", driver_name, driver_version);
+ printk(KERN_INFO "unload %s\n", driver_name);
if (serial_driver) {
for (info=slgt_device_list ; info != NULL ; info=info->next_device)
@@ -3619,7 +3616,7 @@ static int __init slgt_init(void)
{
int rc;
- printk("%s %s\n", driver_name, driver_version);
+ printk(KERN_INFO "%s\n", driver_name);
serial_driver = alloc_tty_driver(MAX_DEVICES);
if (!serial_driver) {
@@ -3650,9 +3647,8 @@ static int __init slgt_init(void)
goto error;
}
- printk("%s %s, tty major#%d\n",
- driver_name, driver_version,
- serial_driver->major);
+ printk(KERN_INFO "%s, tty major#%d\n",
+ driver_name, serial_driver->major);
slgt_device_count = 0;
if ((rc = pci_register_driver(&pci_driver)) < 0) {
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index d41b9f6f7903..33a9351c896d 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -473,6 +473,12 @@ void __handle_sysrq(int key, struct tty_struct *tty, int check_mask)
unsigned long flags;
spin_lock_irqsave(&sysrq_key_table_lock, flags);
+ /*
+ * Raise the apparent loglevel to maximum so that the sysrq header
+ * is shown to provide the user with positive feedback. We do not
+ * simply emit this at KERN_EMERG as that would change message
+ * routing in the consumers of /proc/kmsg.
+ */
orig_log_level = console_loglevel;
console_loglevel = 7;
printk(KERN_INFO "SysRq : ");
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
index 68f052b42ed7..ed306eb1057f 100644
--- a/drivers/char/tpm/tpm_bios.c
+++ b/drivers/char/tpm/tpm_bios.c
@@ -23,8 +23,6 @@
#include <linux/security.h>
#include <linux/module.h>
#include <acpi/acpi.h>
-#include <acpi/actypes.h>
-#include <acpi/actbl.h>
#include "tpm.h"
#define TCG_EVENT_NAME_LEN_MAX 255
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index ab18c1e7b115..70efba2ee053 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -273,12 +273,23 @@ static void tpm_nsc_remove(struct device *dev)
}
}
-static struct device_driver nsc_drv = {
- .name = "tpm_nsc",
- .bus = &platform_bus_type,
- .owner = THIS_MODULE,
- .suspend = tpm_pm_suspend,
- .resume = tpm_pm_resume,
+static int tpm_nsc_suspend(struct platform_device *dev, pm_message_t msg)
+{
+ return tpm_pm_suspend(&dev->dev, msg);
+}
+
+static int tpm_nsc_resume(struct platform_device *dev)
+{
+ return tpm_pm_resume(&dev->dev);
+}
+
+static struct platform_driver nsc_drv = {
+ .suspend = tpm_nsc_suspend,
+ .resume = tpm_nsc_resume,
+ .driver = {
+ .name = "tpm_nsc",
+ .owner = THIS_MODULE,
+ },
};
static int __init init_nsc(void)
@@ -297,7 +308,7 @@ static int __init init_nsc(void)
return -ENODEV;
}
- err = driver_register(&nsc_drv);
+ err = platform_driver_register(&nsc_drv);
if (err)
return err;
@@ -308,17 +319,15 @@ static int __init init_nsc(void)
/* enable the DPM module */
tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01);
- pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
+ pdev = platform_device_alloc("tpm_nscl0", -1);
if (!pdev) {
rc = -ENOMEM;
goto err_unreg_drv;
}
- pdev->name = "tpm_nscl0";
- pdev->id = -1;
pdev->num_resources = 0;
+ pdev->dev.driver = &nsc_drv.driver;
pdev->dev.release = tpm_nsc_remove;
- pdev->dev.driver = &nsc_drv;
if ((rc = platform_device_register(pdev)) < 0)
goto err_free_dev;
@@ -377,7 +386,7 @@ err_unreg_dev:
err_free_dev:
kfree(pdev);
err_unreg_drv:
- driver_unregister(&nsc_drv);
+ platform_driver_unregister(&nsc_drv);
return rc;
}
@@ -390,7 +399,7 @@ static void __exit cleanup_nsc(void)
pdev = NULL;
}
- driver_unregister(&nsc_drv);
+ platform_driver_unregister(&nsc_drv);
}
module_init(init_nsc);
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index a408c8e487ec..6f4c7d0a53bf 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -1057,7 +1057,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
if (retval)
return retval;
- ld = tty_ldisc_ref(tty);
+ ld = tty_ldisc_ref_wait(tty);
switch (arg) {
case TCIFLUSH:
if (ld && ld->ops->flush_buffer)
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index 0e8234bd0e19..994e1a58b987 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -198,6 +198,7 @@ static void scc_init_portstructs(void)
static int mvme147_scc_init(void)
{
struct scc_port *port;
+ int error;
printk(KERN_INFO "SCC: MVME147 Serial Driver\n");
/* Init channel A */
@@ -207,14 +208,23 @@ static int mvme147_scc_init(void)
port->datap = port->ctrlp + 1;
port->port_a = &scc_ports[0];
port->port_b = &scc_ports[1];
- request_irq(MVME147_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
+ error = request_irq(MVME147_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
"SCC-A TX", port);
- request_irq(MVME147_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
+ if (error)
+ goto fail;
+ error = request_irq(MVME147_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
"SCC-A status", port);
- request_irq(MVME147_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
+ if (error)
+ goto fail_free_a_tx;
+ error = request_irq(MVME147_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
"SCC-A RX", port);
- request_irq(MVME147_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED,
- "SCC-A special cond", port);
+ if (error)
+ goto fail_free_a_stat;
+ error = request_irq(MVME147_IRQ_SCCA_SPCOND, scc_spcond_int,
+ IRQF_DISABLED, "SCC-A special cond", port);
+ if (error)
+ goto fail_free_a_rx;
+
{
SCC_ACCESS_INIT(port);
@@ -234,14 +244,23 @@ static int mvme147_scc_init(void)
port->datap = port->ctrlp + 1;
port->port_a = &scc_ports[0];
port->port_b = &scc_ports[1];
- request_irq(MVME147_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
+ error = request_irq(MVME147_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
"SCC-B TX", port);
- request_irq(MVME147_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
+ if (error)
+ goto fail_free_a_spcond;
+ error = request_irq(MVME147_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
"SCC-B status", port);
- request_irq(MVME147_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
+ if (error)
+ goto fail_free_b_tx;
+ error = request_irq(MVME147_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
"SCC-B RX", port);
- request_irq(MVME147_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED,
- "SCC-B special cond", port);
+ if (error)
+ goto fail_free_b_stat;
+ error = request_irq(MVME147_IRQ_SCCB_SPCOND, scc_spcond_int,
+ IRQF_DISABLED, "SCC-B special cond", port);
+ if (error)
+ goto fail_free_b_rx;
+
{
SCC_ACCESS_INIT(port);
@@ -257,6 +276,23 @@ static int mvme147_scc_init(void)
scc_init_drivers();
return 0;
+
+fail_free_b_rx:
+ free_irq(MVME147_IRQ_SCCB_RX, port);
+fail_free_b_stat:
+ free_irq(MVME147_IRQ_SCCB_STAT, port);
+fail_free_b_tx:
+ free_irq(MVME147_IRQ_SCCB_TX, port);
+fail_free_a_spcond:
+ free_irq(MVME147_IRQ_SCCA_SPCOND, port);
+fail_free_a_rx:
+ free_irq(MVME147_IRQ_SCCA_RX, port);
+fail_free_a_stat:
+ free_irq(MVME147_IRQ_SCCA_STAT, port);
+fail_free_a_tx:
+ free_irq(MVME147_IRQ_SCCA_TX, port);
+fail:
+ return error;
}
#endif
@@ -265,6 +301,7 @@ static int mvme147_scc_init(void)
static int mvme162_scc_init(void)
{
struct scc_port *port;
+ int error;
if (!(mvme16x_config & MVME16x_CONFIG_GOT_SCCA))
return (-ENODEV);
@@ -277,14 +314,23 @@ static int mvme162_scc_init(void)
port->datap = port->ctrlp + 2;
port->port_a = &scc_ports[0];
port->port_b = &scc_ports[1];
- request_irq(MVME162_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
+ error = request_irq(MVME162_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
"SCC-A TX", port);
- request_irq(MVME162_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
+ if (error)
+ goto fail;
+ error = request_irq(MVME162_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
"SCC-A status", port);
- request_irq(MVME162_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
+ if (error)
+ goto fail_free_a_tx;
+ error = request_irq(MVME162_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
"SCC-A RX", port);
- request_irq(MVME162_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED,
- "SCC-A special cond", port);
+ if (error)
+ goto fail_free_a_stat;
+ error = request_irq(MVME162_IRQ_SCCA_SPCOND, scc_spcond_int,
+ IRQF_DISABLED, "SCC-A special cond", port);
+ if (error)
+ goto fail_free_a_rx;
+
{
SCC_ACCESS_INIT(port);
@@ -304,14 +350,22 @@ static int mvme162_scc_init(void)
port->datap = port->ctrlp + 2;
port->port_a = &scc_ports[0];
port->port_b = &scc_ports[1];
- request_irq(MVME162_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
+ error = request_irq(MVME162_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
"SCC-B TX", port);
- request_irq(MVME162_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
+ if (error)
+ goto fail_free_a_spcond;
+ error = request_irq(MVME162_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
"SCC-B status", port);
- request_irq(MVME162_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
+ if (error)
+ goto fail_free_b_tx;
+ error = request_irq(MVME162_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
"SCC-B RX", port);
- request_irq(MVME162_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED,
- "SCC-B special cond", port);
+ if (error)
+ goto fail_free_b_stat;
+ error = request_irq(MVME162_IRQ_SCCB_SPCOND, scc_spcond_int,
+ IRQF_DISABLED, "SCC-B special cond", port);
+ if (error)
+ goto fail_free_b_rx;
{
SCC_ACCESS_INIT(port); /* Either channel will do */
@@ -328,6 +382,23 @@ static int mvme162_scc_init(void)
scc_init_drivers();
return 0;
+
+fail_free_b_rx:
+ free_irq(MVME162_IRQ_SCCB_RX, port);
+fail_free_b_stat:
+ free_irq(MVME162_IRQ_SCCB_STAT, port);
+fail_free_b_tx:
+ free_irq(MVME162_IRQ_SCCB_TX, port);
+fail_free_a_spcond:
+ free_irq(MVME162_IRQ_SCCA_SPCOND, port);
+fail_free_a_rx:
+ free_irq(MVME162_IRQ_SCCA_RX, port);
+fail_free_a_stat:
+ free_irq(MVME162_IRQ_SCCA_STAT, port);
+fail_free_a_tx:
+ free_irq(MVME162_IRQ_SCCA_TX, port);
+fail:
+ return error;
}
#endif
@@ -336,6 +407,7 @@ static int mvme162_scc_init(void)
static int bvme6000_scc_init(void)
{
struct scc_port *port;
+ int error;
printk(KERN_INFO "SCC: BVME6000 Serial Driver\n");
/* Init channel A */
@@ -345,14 +417,23 @@ static int bvme6000_scc_init(void)
port->datap = port->ctrlp + 4;
port->port_a = &scc_ports[0];
port->port_b = &scc_ports[1];
- request_irq(BVME_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
+ error = request_irq(BVME_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
"SCC-A TX", port);
- request_irq(BVME_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
+ if (error)
+ goto fail;
+ error = request_irq(BVME_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
"SCC-A status", port);
- request_irq(BVME_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
+ if (error)
+ goto fail_free_a_tx;
+ error = request_irq(BVME_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
"SCC-A RX", port);
- request_irq(BVME_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED,
- "SCC-A special cond", port);
+ if (error)
+ goto fail_free_a_stat;
+ error = request_irq(BVME_IRQ_SCCA_SPCOND, scc_spcond_int,
+ IRQF_DISABLED, "SCC-A special cond", port);
+ if (error)
+ goto fail_free_a_rx;
+
{
SCC_ACCESS_INIT(port);
@@ -372,14 +453,22 @@ static int bvme6000_scc_init(void)
port->datap = port->ctrlp + 4;
port->port_a = &scc_ports[0];
port->port_b = &scc_ports[1];
- request_irq(BVME_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
+ error = request_irq(BVME_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
"SCC-B TX", port);
- request_irq(BVME_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
+ if (error)
+ goto fail_free_a_spcond;
+ error = request_irq(BVME_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
"SCC-B status", port);
- request_irq(BVME_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
+ if (error)
+ goto fail_free_b_tx;
+ error = request_irq(BVME_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
"SCC-B RX", port);
- request_irq(BVME_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED,
- "SCC-B special cond", port);
+ if (error)
+ goto fail_free_b_stat;
+ error = request_irq(BVME_IRQ_SCCB_SPCOND, scc_spcond_int,
+ IRQF_DISABLED, "SCC-B special cond", port);
+ if (error)
+ goto fail_free_b_rx;
{
SCC_ACCESS_INIT(port); /* Either channel will do */
@@ -393,6 +482,23 @@ static int bvme6000_scc_init(void)
scc_init_drivers();
return 0;
+
+fail:
+ free_irq(BVME_IRQ_SCCA_STAT, port);
+fail_free_a_tx:
+ free_irq(BVME_IRQ_SCCA_RX, port);
+fail_free_a_stat:
+ free_irq(BVME_IRQ_SCCA_SPCOND, port);
+fail_free_a_rx:
+ free_irq(BVME_IRQ_SCCB_TX, port);
+fail_free_a_spcond:
+ free_irq(BVME_IRQ_SCCB_STAT, port);
+fail_free_b_tx:
+ free_irq(BVME_IRQ_SCCB_RX, port);
+fail_free_b_stat:
+ free_irq(BVME_IRQ_SCCB_SPCOND, port);
+fail_free_b_rx:
+ return error;
}
#endif
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 80014213fb53..7900bd63b36d 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -969,8 +969,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
* Takes the console sem and the called methods then take the tty
* termios_mutex and the tty ctrl_lock in that order.
*/
-
-int vt_resize(struct tty_struct *tty, struct winsize *ws)
+static int vt_resize(struct tty_struct *tty, struct winsize *ws)
{
struct vc_data *vc = tty->driver_data;
int ret;
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 5f076aef74fa..a8c8d9c19d74 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -83,7 +83,7 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE
select CPU_FREQ_GOV_USERSPACE
help
Use the CPUFreq governor 'userspace' as default. This allows
- you to set the CPU frequency manually or when an userspace
+ you to set the CPU frequency manually or when a userspace
program shall be able to set the CPU dynamically without having
to enable the userspace governor manually.
@@ -138,7 +138,7 @@ config CPU_FREQ_GOV_USERSPACE
tristate "'userspace' governor for userspace frequency scaling"
help
Enable this cpufreq governor when you either want to set the
- CPU frequency manually or when an userspace program shall
+ CPU frequency manually or when a userspace program shall
be able to set the CPU dynamically, like on LART
<http://www.lartmaker.nl/>.
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 01dde80597f7..b55cb67435bd 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -584,12 +584,12 @@ out:
return i;
}
-static ssize_t show_cpus(cpumask_t mask, char *buf)
+static ssize_t show_cpus(const struct cpumask *mask, char *buf)
{
ssize_t i = 0;
unsigned int cpu;
- for_each_cpu_mask_nr(cpu, mask) {
+ for_each_cpu(cpu, mask) {
if (i)
i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " ");
i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu);
@@ -606,7 +606,7 @@ static ssize_t show_cpus(cpumask_t mask, char *buf)
*/
static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf)
{
- if (cpus_empty(policy->related_cpus))
+ if (cpumask_empty(policy->related_cpus))
return show_cpus(policy->cpus, buf);
return show_cpus(policy->related_cpus, buf);
}
@@ -806,9 +806,20 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
ret = -ENOMEM;
goto nomem_out;
}
+ if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) {
+ kfree(policy);
+ ret = -ENOMEM;
+ goto nomem_out;
+ }
+ if (!alloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) {
+ free_cpumask_var(policy->cpus);
+ kfree(policy);
+ ret = -ENOMEM;
+ goto nomem_out;
+ }
policy->cpu = cpu;
- policy->cpus = cpumask_of_cpu(cpu);
+ cpumask_copy(policy->cpus, cpumask_of(cpu));
/* Initially set CPU itself as the policy_cpu */
per_cpu(policy_cpu, cpu) = cpu;
@@ -843,7 +854,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
}
#endif
- for_each_cpu_mask_nr(j, policy->cpus) {
+ for_each_cpu(j, policy->cpus) {
if (cpu == j)
continue;
@@ -861,7 +872,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
goto err_out_driver_exit;
spin_lock_irqsave(&cpufreq_driver_lock, flags);
- managed_policy->cpus = policy->cpus;
+ cpumask_copy(managed_policy->cpus, policy->cpus);
per_cpu(cpufreq_cpu_data, cpu) = managed_policy;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -916,14 +927,14 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
}
spin_lock_irqsave(&cpufreq_driver_lock, flags);
- for_each_cpu_mask_nr(j, policy->cpus) {
+ for_each_cpu(j, policy->cpus) {
per_cpu(cpufreq_cpu_data, j) = policy;
per_cpu(policy_cpu, j) = policy->cpu;
}
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
/* symlink affected CPUs */
- for_each_cpu_mask_nr(j, policy->cpus) {
+ for_each_cpu(j, policy->cpus) {
if (j == cpu)
continue;
if (!cpu_online(j))
@@ -963,7 +974,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
err_out_unregister:
spin_lock_irqsave(&cpufreq_driver_lock, flags);
- for_each_cpu_mask_nr(j, policy->cpus)
+ for_each_cpu(j, policy->cpus)
per_cpu(cpufreq_cpu_data, j) = NULL;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -1024,7 +1035,7 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
*/
if (unlikely(cpu != data->cpu)) {
dprintk("removing link\n");
- cpu_clear(cpu, data->cpus);
+ cpumask_clear_cpu(cpu, data->cpus);
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
sysfs_remove_link(&sys_dev->kobj, "cpufreq");
cpufreq_cpu_put(data);
@@ -1045,8 +1056,8 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
* per_cpu(cpufreq_cpu_data) while holding the lock, and remove
* the sysfs links afterwards.
*/
- if (unlikely(cpus_weight(data->cpus) > 1)) {
- for_each_cpu_mask_nr(j, data->cpus) {
+ if (unlikely(cpumask_weight(data->cpus) > 1)) {
+ for_each_cpu(j, data->cpus) {
if (j == cpu)
continue;
per_cpu(cpufreq_cpu_data, j) = NULL;
@@ -1055,8 +1066,8 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
- if (unlikely(cpus_weight(data->cpus) > 1)) {
- for_each_cpu_mask_nr(j, data->cpus) {
+ if (unlikely(cpumask_weight(data->cpus) > 1)) {
+ for_each_cpu(j, data->cpus) {
if (j == cpu)
continue;
dprintk("removing link for cpu %u\n", j);
@@ -1090,7 +1101,10 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
if (cpufreq_driver->exit)
cpufreq_driver->exit(data);
+ free_cpumask_var(data->related_cpus);
+ free_cpumask_var(data->cpus);
kfree(data);
+ per_cpu(cpufreq_cpu_data, cpu) = NULL;
cpufreq_debug_enable_ratelimit();
return 0;
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index e2657837d954..0320962c4ec5 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -498,7 +498,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return rc;
}
- for_each_cpu_mask_nr(j, policy->cpus) {
+ for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
j_dbs_info->cur_policy = policy;
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 2ab3c12b88af..6a2b036c9389 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -400,7 +400,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
/* Get Absolute Load - in terms of freq */
max_load_freq = 0;
- for_each_cpu_mask_nr(j, policy->cpus) {
+ for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
cputime64_t cur_wall_time, cur_idle_time;
unsigned int idle_time, wall_time;
@@ -568,7 +568,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return rc;
}
- for_each_cpu_mask_nr(j, policy->cpus) {
+ for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
j_dbs_info->cur_policy = policy;
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 8d7cf3f31450..f1df59f59a37 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -15,12 +15,14 @@
#include <linux/tick.h>
#define BREAK_FUZZ 4 /* 4 us */
+#define PRED_HISTORY_PCT 50
struct menu_device {
int last_state_idx;
unsigned int expected_us;
unsigned int predicted_us;
+ unsigned int current_predicted_us;
unsigned int last_measured_us;
unsigned int elapsed_us;
};
@@ -47,6 +49,12 @@ static int menu_select(struct cpuidle_device *dev)
data->expected_us =
(u32) ktime_to_ns(tick_nohz_get_sleep_length()) / 1000;
+ /* Recalculate predicted_us based on prediction_history_pct */
+ data->predicted_us *= PRED_HISTORY_PCT;
+ data->predicted_us += (100 - PRED_HISTORY_PCT) *
+ data->current_predicted_us;
+ data->predicted_us /= 100;
+
/* find the deepest idle state that satisfies our constraints */
for (i = CPUIDLE_DRIVER_STATE_START + 1; i < dev->state_count; i++) {
struct cpuidle_state *s = &dev->states[i];
@@ -97,7 +105,7 @@ static void menu_reflect(struct cpuidle_device *dev)
measured_us = -1;
/* Predict time until next break event */
- data->predicted_us = max(measured_us, data->last_measured_us);
+ data->current_predicted_us = max(measured_us, data->last_measured_us);
if (last_idle_us + BREAK_FUZZ <
data->expected_us - target->exit_latency) {
diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c
index d883e1b8bb8c..55433849bfa6 100644
--- a/drivers/dca/dca-core.c
+++ b/drivers/dca/dca-core.c
@@ -270,6 +270,6 @@ static void __exit dca_exit(void)
dca_sysfs_exit();
}
-subsys_initcall(dca_init);
+arch_initcall(dca_init);
module_exit(dca_exit);
diff --git a/drivers/dio/dio-sysfs.c b/drivers/dio/dio-sysfs.c
index f46463038847..ee1a3b59bd4e 100644
--- a/drivers/dio/dio-sysfs.c
+++ b/drivers/dio/dio-sysfs.c
@@ -58,20 +58,25 @@ static ssize_t dio_show_resource(struct device *dev, struct device_attribute *at
struct dio_dev *d = to_dio_dev(dev);
return sprintf(buf, "0x%08lx 0x%08lx 0x%08lx\n",
- dio_resource_start(d), dio_resource_end(d),
+ (unsigned long)dio_resource_start(d),
+ (unsigned long)dio_resource_end(d),
dio_resource_flags(d));
}
static DEVICE_ATTR(resource, S_IRUGO, dio_show_resource, NULL);
-void dio_create_sysfs_dev_files(struct dio_dev *d)
+int dio_create_sysfs_dev_files(struct dio_dev *d)
{
struct device *dev = &d->dev;
+ int error;
/* current configuration's attributes */
- device_create_file(dev, &dev_attr_id);
- device_create_file(dev, &dev_attr_ipl);
- device_create_file(dev, &dev_attr_secid);
- device_create_file(dev, &dev_attr_name);
- device_create_file(dev, &dev_attr_resource);
+ if ((error = device_create_file(dev, &dev_attr_id)) ||
+ (error = device_create_file(dev, &dev_attr_ipl)) ||
+ (error = device_create_file(dev, &dev_attr_secid)) ||
+ (error = device_create_file(dev, &dev_attr_name)) ||
+ (error = device_create_file(dev, &dev_attr_resource)))
+ return error;
+
+ return 0;
}
diff --git a/drivers/dio/dio.c b/drivers/dio/dio.c
index 07f274f853d9..10c3c498358c 100644
--- a/drivers/dio/dio.c
+++ b/drivers/dio/dio.c
@@ -173,6 +173,7 @@ static int __init dio_init(void)
mm_segment_t fs;
int i;
struct dio_dev *dev;
+ int error;
if (!MACH_IS_HP300)
return 0;
@@ -182,7 +183,11 @@ static int __init dio_init(void)
/* Initialize the DIO bus */
INIT_LIST_HEAD(&dio_bus.devices);
strcpy(dio_bus.dev.bus_id, "dio");
- device_register(&dio_bus.dev);
+ error = device_register(&dio_bus.dev);
+ if (error) {
+ pr_err("DIO: Error registering dio_bus\n");
+ return error;
+ }
/* Request all resources */
dio_bus.num_resources = (hp300_model == HP_320 ? 1 : 2);
@@ -252,8 +257,15 @@ static int __init dio_init(void)
if (scode >= DIOII_SCBASE)
iounmap(va);
- device_register(&dev->dev);
- dio_create_sysfs_dev_files(dev);
+ error = device_register(&dev->dev);
+ if (error) {
+ pr_err("DIO: Error registering device %s\n",
+ dev->name);
+ continue;
+ }
+ error = dio_create_sysfs_dev_files(dev);
+ if (error)
+ dev_err(&dev->dev, "Error creating sysfs files\n");
}
return 0;
}
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 904e57558bb5..e34b06420816 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -33,7 +33,6 @@ config INTEL_IOATDMA
config INTEL_IOP_ADMA
tristate "Intel IOP ADMA support"
depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX
- select ASYNC_CORE
select DMA_ENGINE
help
Enable support for the Intel(R) IOP Series RAID engines.
@@ -59,7 +58,6 @@ config FSL_DMA
config MV_XOR
bool "Marvell XOR engine support"
depends on PLAT_ORION
- select ASYNC_CORE
select DMA_ENGINE
---help---
Enable support for the Marvell XOR engine.
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 657996517374..403dbe781122 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -31,32 +31,18 @@
*
* LOCKING:
*
- * The subsystem keeps two global lists, dma_device_list and dma_client_list.
- * Both of these are protected by a mutex, dma_list_mutex.
+ * The subsystem keeps a global list of dma_device structs it is protected by a
+ * mutex, dma_list_mutex.
+ *
+ * A subsystem can get access to a channel by calling dmaengine_get() followed
+ * by dma_find_channel(), or if it has need for an exclusive channel it can call
+ * dma_request_channel(). Once a channel is allocated a reference is taken
+ * against its corresponding driver to disable removal.
*
* Each device has a channels list, which runs unlocked but is never modified
* once the device is registered, it's just setup by the driver.
*
- * Each client is responsible for keeping track of the channels it uses. See
- * 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 device registered. When the
- * device is released, the corresponding 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 corresponding kref_put
- * happens. The device's release function does a completion, so
- * 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.
- *
- * Each channel has an open-coded implementation of Rusty Russell's "bigref,"
- * with a kref and a per_cpu local_t. A dma_chan_get is called when a client
- * signals that it wants to use a channel, and dma_chan_put is called when
- * a channel is removed or a client using it is unregistered. A client can
- * take extra references per outstanding transaction, as is the case with
- * the NET DMA client. The release function does a kref_put on the device.
- * -ChrisL, DanW
+ * See Documentation/dmaengine.txt for more details
*/
#include <linux/init.h>
@@ -70,54 +56,85 @@
#include <linux/rcupdate.h>
#include <linux/mutex.h>
#include <linux/jiffies.h>
+#include <linux/rculist.h>
+#include <linux/idr.h>
static DEFINE_MUTEX(dma_list_mutex);
static LIST_HEAD(dma_device_list);
-static LIST_HEAD(dma_client_list);
+static long dmaengine_ref_count;
+static struct idr dma_idr;
/* --- sysfs implementation --- */
+/**
+ * dev_to_dma_chan - convert a device pointer to the its sysfs container object
+ * @dev - device node
+ *
+ * Must be called under dma_list_mutex
+ */
+static struct dma_chan *dev_to_dma_chan(struct device *dev)
+{
+ struct dma_chan_dev *chan_dev;
+
+ chan_dev = container_of(dev, typeof(*chan_dev), device);
+ return chan_dev->chan;
+}
+
static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct dma_chan *chan = to_dma_chan(dev);
+ struct dma_chan *chan;
unsigned long count = 0;
int i;
+ int err;
- for_each_possible_cpu(i)
- count += per_cpu_ptr(chan->local, i)->memcpy_count;
+ mutex_lock(&dma_list_mutex);
+ chan = dev_to_dma_chan(dev);
+ if (chan) {
+ for_each_possible_cpu(i)
+ count += per_cpu_ptr(chan->local, i)->memcpy_count;
+ err = sprintf(buf, "%lu\n", count);
+ } else
+ err = -ENODEV;
+ mutex_unlock(&dma_list_mutex);
- return sprintf(buf, "%lu\n", count);
+ return err;
}
static ssize_t show_bytes_transferred(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct dma_chan *chan = to_dma_chan(dev);
+ struct dma_chan *chan;
unsigned long count = 0;
int i;
+ int err;
- for_each_possible_cpu(i)
- count += per_cpu_ptr(chan->local, i)->bytes_transferred;
+ mutex_lock(&dma_list_mutex);
+ chan = dev_to_dma_chan(dev);
+ if (chan) {
+ for_each_possible_cpu(i)
+ count += per_cpu_ptr(chan->local, i)->bytes_transferred;
+ err = sprintf(buf, "%lu\n", count);
+ } else
+ err = -ENODEV;
+ mutex_unlock(&dma_list_mutex);
- return sprintf(buf, "%lu\n", count);
+ return err;
}
static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct dma_chan *chan = to_dma_chan(dev);
- int in_use = 0;
-
- if (unlikely(chan->slow_ref) &&
- atomic_read(&chan->refcount.refcount) > 1)
- in_use = 1;
- else {
- if (local_read(&(per_cpu_ptr(chan->local,
- get_cpu())->refcount)) > 0)
- in_use = 1;
- put_cpu();
- }
+ struct dma_chan *chan;
+ int err;
- return sprintf(buf, "%d\n", in_use);
+ mutex_lock(&dma_list_mutex);
+ chan = dev_to_dma_chan(dev);
+ if (chan)
+ err = sprintf(buf, "%d\n", chan->client_count);
+ else
+ err = -ENODEV;
+ mutex_unlock(&dma_list_mutex);
+
+ return err;
}
static struct device_attribute dma_attrs[] = {
@@ -127,76 +144,110 @@ static struct device_attribute dma_attrs[] = {
__ATTR_NULL
};
-static void dma_async_device_cleanup(struct kref *kref);
-
-static void dma_dev_release(struct device *dev)
+static void chan_dev_release(struct device *dev)
{
- struct dma_chan *chan = to_dma_chan(dev);
- kref_put(&chan->device->refcount, dma_async_device_cleanup);
+ struct dma_chan_dev *chan_dev;
+
+ chan_dev = container_of(dev, typeof(*chan_dev), device);
+ if (atomic_dec_and_test(chan_dev->idr_ref)) {
+ mutex_lock(&dma_list_mutex);
+ idr_remove(&dma_idr, chan_dev->dev_id);
+ mutex_unlock(&dma_list_mutex);
+ kfree(chan_dev->idr_ref);
+ }
+ kfree(chan_dev);
}
static struct class dma_devclass = {
.name = "dma",
.dev_attrs = dma_attrs,
- .dev_release = dma_dev_release,
+ .dev_release = chan_dev_release,
};
/* --- client and device registration --- */
-#define dma_chan_satisfies_mask(chan, mask) \
- __dma_chan_satisfies_mask((chan), &(mask))
+#define dma_device_satisfies_mask(device, mask) \
+ __dma_device_satisfies_mask((device), &(mask))
static int
-__dma_chan_satisfies_mask(struct dma_chan *chan, dma_cap_mask_t *want)
+__dma_device_satisfies_mask(struct dma_device *device, dma_cap_mask_t *want)
{
dma_cap_mask_t has;
- bitmap_and(has.bits, want->bits, chan->device->cap_mask.bits,
+ bitmap_and(has.bits, want->bits, device->cap_mask.bits,
DMA_TX_TYPE_END);
return bitmap_equal(want->bits, has.bits, DMA_TX_TYPE_END);
}
+static struct module *dma_chan_to_owner(struct dma_chan *chan)
+{
+ return chan->device->dev->driver->owner;
+}
+
/**
- * dma_client_chan_alloc - try to allocate channels to a client
- * @client: &dma_client
+ * balance_ref_count - catch up the channel reference count
+ * @chan - channel to balance ->client_count versus dmaengine_ref_count
*
- * Called with dma_list_mutex held.
+ * balance_ref_count must be called under dma_list_mutex
*/
-static void dma_client_chan_alloc(struct dma_client *client)
+static void balance_ref_count(struct dma_chan *chan)
{
- struct dma_device *device;
- struct dma_chan *chan;
- int desc; /* allocated descriptor count */
- enum dma_state_client ack;
+ struct module *owner = dma_chan_to_owner(chan);
- /* Find a channel */
- list_for_each_entry(device, &dma_device_list, global_node) {
- /* Does the client require a specific DMA controller? */
- if (client->slave && client->slave->dma_dev
- && client->slave->dma_dev != device->dev)
- continue;
+ while (chan->client_count < dmaengine_ref_count) {
+ __module_get(owner);
+ chan->client_count++;
+ }
+}
- list_for_each_entry(chan, &device->channels, device_node) {
- if (!dma_chan_satisfies_mask(chan, client->cap_mask))
- continue;
+/**
+ * dma_chan_get - try to grab a dma channel's parent driver module
+ * @chan - channel to grab
+ *
+ * Must be called under dma_list_mutex
+ */
+static int dma_chan_get(struct dma_chan *chan)
+{
+ int err = -ENODEV;
+ struct module *owner = dma_chan_to_owner(chan);
+
+ if (chan->client_count) {
+ __module_get(owner);
+ err = 0;
+ } else if (try_module_get(owner))
+ err = 0;
+
+ if (err == 0)
+ chan->client_count++;
+
+ /* allocate upon first client reference */
+ if (chan->client_count == 1 && err == 0) {
+ int desc_cnt = chan->device->device_alloc_chan_resources(chan);
+
+ if (desc_cnt < 0) {
+ err = desc_cnt;
+ chan->client_count = 0;
+ module_put(owner);
+ } else if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask))
+ balance_ref_count(chan);
+ }
- desc = chan->device->device_alloc_chan_resources(
- chan, client);
- if (desc >= 0) {
- ack = client->event_callback(client,
- chan,
- DMA_RESOURCE_AVAILABLE);
+ return err;
+}
- /* we are done once this client rejects
- * an available resource
- */
- if (ack == DMA_ACK) {
- dma_chan_get(chan);
- chan->client_count++;
- } else if (ack == DMA_NAK)
- return;
- }
- }
- }
+/**
+ * dma_chan_put - drop a reference to a dma channel's parent driver module
+ * @chan - channel to release
+ *
+ * Must be called under dma_list_mutex
+ */
+static void dma_chan_put(struct dma_chan *chan)
+{
+ if (!chan->client_count)
+ return; /* this channel failed alloc_chan_resources */
+ chan->client_count--;
+ module_put(dma_chan_to_owner(chan));
+ if (chan->client_count == 0)
+ chan->device->device_free_chan_resources(chan);
}
enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie)
@@ -218,138 +269,342 @@ enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie)
EXPORT_SYMBOL(dma_sync_wait);
/**
- * dma_chan_cleanup - release a DMA channel's resources
- * @kref: kernel reference structure that contains the DMA channel device
+ * dma_cap_mask_all - enable iteration over all operation types
+ */
+static dma_cap_mask_t dma_cap_mask_all;
+
+/**
+ * dma_chan_tbl_ent - tracks channel allocations per core/operation
+ * @chan - associated channel for this entry
+ */
+struct dma_chan_tbl_ent {
+ struct dma_chan *chan;
+};
+
+/**
+ * channel_table - percpu lookup table for memory-to-memory offload providers
*/
-void dma_chan_cleanup(struct kref *kref)
+static struct dma_chan_tbl_ent *channel_table[DMA_TX_TYPE_END];
+
+static int __init dma_channel_table_init(void)
{
- struct dma_chan *chan = container_of(kref, struct dma_chan, refcount);
- chan->device->device_free_chan_resources(chan);
- kref_put(&chan->device->refcount, dma_async_device_cleanup);
+ enum dma_transaction_type cap;
+ int err = 0;
+
+ bitmap_fill(dma_cap_mask_all.bits, DMA_TX_TYPE_END);
+
+ /* 'interrupt', 'private', and 'slave' are channel capabilities,
+ * but are not associated with an operation so they do not need
+ * an entry in the channel_table
+ */
+ clear_bit(DMA_INTERRUPT, dma_cap_mask_all.bits);
+ clear_bit(DMA_PRIVATE, dma_cap_mask_all.bits);
+ clear_bit(DMA_SLAVE, dma_cap_mask_all.bits);
+
+ for_each_dma_cap_mask(cap, dma_cap_mask_all) {
+ channel_table[cap] = alloc_percpu(struct dma_chan_tbl_ent);
+ if (!channel_table[cap]) {
+ err = -ENOMEM;
+ break;
+ }
+ }
+
+ if (err) {
+ pr_err("dmaengine: initialization failure\n");
+ for_each_dma_cap_mask(cap, dma_cap_mask_all)
+ if (channel_table[cap])
+ free_percpu(channel_table[cap]);
+ }
+
+ return err;
}
-EXPORT_SYMBOL(dma_chan_cleanup);
+arch_initcall(dma_channel_table_init);
-static void dma_chan_free_rcu(struct rcu_head *rcu)
+/**
+ * dma_find_channel - find a channel to carry out the operation
+ * @tx_type: transaction type
+ */
+struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type)
{
- struct dma_chan *chan = container_of(rcu, struct dma_chan, rcu);
- int bias = 0x7FFFFFFF;
- int i;
- for_each_possible_cpu(i)
- bias -= local_read(&per_cpu_ptr(chan->local, i)->refcount);
- atomic_sub(bias, &chan->refcount.refcount);
- kref_put(&chan->refcount, dma_chan_cleanup);
+ struct dma_chan *chan;
+ int cpu;
+
+ WARN_ONCE(dmaengine_ref_count == 0,
+ "client called %s without a reference", __func__);
+
+ cpu = get_cpu();
+ chan = per_cpu_ptr(channel_table[tx_type], cpu)->chan;
+ put_cpu();
+
+ return chan;
}
+EXPORT_SYMBOL(dma_find_channel);
-static void dma_chan_release(struct dma_chan *chan)
+/**
+ * dma_issue_pending_all - flush all pending operations across all channels
+ */
+void dma_issue_pending_all(void)
{
- atomic_add(0x7FFFFFFF, &chan->refcount.refcount);
- chan->slow_ref = 1;
- call_rcu(&chan->rcu, dma_chan_free_rcu);
+ struct dma_device *device;
+ struct dma_chan *chan;
+
+ WARN_ONCE(dmaengine_ref_count == 0,
+ "client called %s without a reference", __func__);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(device, &dma_device_list, global_node) {
+ if (dma_has_cap(DMA_PRIVATE, device->cap_mask))
+ continue;
+ list_for_each_entry(chan, &device->channels, device_node)
+ if (chan->client_count)
+ device->device_issue_pending(chan);
+ }
+ rcu_read_unlock();
}
+EXPORT_SYMBOL(dma_issue_pending_all);
/**
- * dma_chans_notify_available - broadcast available channels to the clients
+ * nth_chan - returns the nth channel of the given capability
+ * @cap: capability to match
+ * @n: nth channel desired
+ *
+ * Defaults to returning the channel with the desired capability and the
+ * lowest reference count when 'n' cannot be satisfied. Must be called
+ * under dma_list_mutex.
*/
-static void dma_clients_notify_available(void)
+static struct dma_chan *nth_chan(enum dma_transaction_type cap, int n)
{
- struct dma_client *client;
+ struct dma_device *device;
+ struct dma_chan *chan;
+ struct dma_chan *ret = NULL;
+ struct dma_chan *min = NULL;
- mutex_lock(&dma_list_mutex);
+ list_for_each_entry(device, &dma_device_list, global_node) {
+ if (!dma_has_cap(cap, device->cap_mask) ||
+ dma_has_cap(DMA_PRIVATE, device->cap_mask))
+ continue;
+ list_for_each_entry(chan, &device->channels, device_node) {
+ if (!chan->client_count)
+ continue;
+ if (!min)
+ min = chan;
+ else if (chan->table_count < min->table_count)
+ min = chan;
+
+ if (n-- == 0) {
+ ret = chan;
+ break; /* done */
+ }
+ }
+ if (ret)
+ break; /* done */
+ }
- list_for_each_entry(client, &dma_client_list, global_node)
- dma_client_chan_alloc(client);
+ if (!ret)
+ ret = min;
- mutex_unlock(&dma_list_mutex);
+ if (ret)
+ ret->table_count++;
+
+ return ret;
}
/**
- * dma_chans_notify_available - tell the clients that a channel is going away
- * @chan: channel on its way out
+ * dma_channel_rebalance - redistribute the available channels
+ *
+ * Optimize for cpu isolation (each cpu gets a dedicated channel for an
+ * operation type) in the SMP case, and operation isolation (avoid
+ * multi-tasking channels) in the non-SMP case. Must be called under
+ * dma_list_mutex.
*/
-static void dma_clients_notify_removed(struct dma_chan *chan)
+static void dma_channel_rebalance(void)
{
- struct dma_client *client;
- enum dma_state_client ack;
+ struct dma_chan *chan;
+ struct dma_device *device;
+ int cpu;
+ int cap;
+ int n;
- mutex_lock(&dma_list_mutex);
+ /* undo the last distribution */
+ for_each_dma_cap_mask(cap, dma_cap_mask_all)
+ for_each_possible_cpu(cpu)
+ per_cpu_ptr(channel_table[cap], cpu)->chan = NULL;
+
+ list_for_each_entry(device, &dma_device_list, global_node) {
+ if (dma_has_cap(DMA_PRIVATE, device->cap_mask))
+ continue;
+ list_for_each_entry(chan, &device->channels, device_node)
+ chan->table_count = 0;
+ }
- list_for_each_entry(client, &dma_client_list, global_node) {
- ack = client->event_callback(client, chan,
- DMA_RESOURCE_REMOVED);
+ /* don't populate the channel_table if no clients are available */
+ if (!dmaengine_ref_count)
+ return;
- /* client was holding resources for this channel so
- * free it
- */
- if (ack == DMA_ACK) {
- dma_chan_put(chan);
- chan->client_count--;
+ /* redistribute available channels */
+ n = 0;
+ for_each_dma_cap_mask(cap, dma_cap_mask_all)
+ for_each_online_cpu(cpu) {
+ if (num_possible_cpus() > 1)
+ chan = nth_chan(cap, n++);
+ else
+ chan = nth_chan(cap, -1);
+
+ per_cpu_ptr(channel_table[cap], cpu)->chan = chan;
+ }
+}
+
+static struct dma_chan *private_candidate(dma_cap_mask_t *mask, struct dma_device *dev,
+ dma_filter_fn fn, void *fn_param)
+{
+ struct dma_chan *chan;
+
+ if (!__dma_device_satisfies_mask(dev, mask)) {
+ pr_debug("%s: wrong capabilities\n", __func__);
+ return NULL;
+ }
+ /* devices with multiple channels need special handling as we need to
+ * ensure that all channels are either private or public.
+ */
+ if (dev->chancnt > 1 && !dma_has_cap(DMA_PRIVATE, dev->cap_mask))
+ list_for_each_entry(chan, &dev->channels, device_node) {
+ /* some channels are already publicly allocated */
+ if (chan->client_count)
+ return NULL;
}
+
+ list_for_each_entry(chan, &dev->channels, device_node) {
+ if (chan->client_count) {
+ pr_debug("%s: %s busy\n",
+ __func__, dma_chan_name(chan));
+ continue;
+ }
+ if (fn && !fn(chan, fn_param)) {
+ pr_debug("%s: %s filter said false\n",
+ __func__, dma_chan_name(chan));
+ continue;
+ }
+ return chan;
}
- mutex_unlock(&dma_list_mutex);
+ return NULL;
}
/**
- * dma_async_client_register - register a &dma_client
- * @client: ptr to a client structure with valid 'event_callback' and 'cap_mask'
+ * dma_request_channel - try to allocate an exclusive channel
+ * @mask: capabilities that the channel must satisfy
+ * @fn: optional callback to disposition available channels
+ * @fn_param: opaque parameter to pass to dma_filter_fn
*/
-void dma_async_client_register(struct dma_client *client)
+struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param)
{
- /* validate client data */
- BUG_ON(dma_has_cap(DMA_SLAVE, client->cap_mask) &&
- !client->slave);
+ struct dma_device *device, *_d;
+ struct dma_chan *chan = NULL;
+ int err;
+ /* Find a channel */
+ mutex_lock(&dma_list_mutex);
+ list_for_each_entry_safe(device, _d, &dma_device_list, global_node) {
+ chan = private_candidate(mask, device, fn, fn_param);
+ if (chan) {
+ /* Found a suitable channel, try to grab, prep, and
+ * return it. We first set DMA_PRIVATE to disable
+ * balance_ref_count as this channel will not be
+ * published in the general-purpose allocator
+ */
+ dma_cap_set(DMA_PRIVATE, device->cap_mask);
+ err = dma_chan_get(chan);
+
+ if (err == -ENODEV) {
+ pr_debug("%s: %s module removed\n", __func__,
+ dma_chan_name(chan));
+ list_del_rcu(&device->global_node);
+ } else if (err)
+ pr_err("dmaengine: failed to get %s: (%d)\n",
+ dma_chan_name(chan), err);
+ else
+ break;
+ chan = NULL;
+ }
+ }
+ mutex_unlock(&dma_list_mutex);
+
+ pr_debug("%s: %s (%s)\n", __func__, chan ? "success" : "fail",
+ chan ? dma_chan_name(chan) : NULL);
+
+ return chan;
+}
+EXPORT_SYMBOL_GPL(__dma_request_channel);
+
+void dma_release_channel(struct dma_chan *chan)
+{
mutex_lock(&dma_list_mutex);
- list_add_tail(&client->global_node, &dma_client_list);
+ WARN_ONCE(chan->client_count != 1,
+ "chan reference count %d != 1\n", chan->client_count);
+ dma_chan_put(chan);
mutex_unlock(&dma_list_mutex);
}
-EXPORT_SYMBOL(dma_async_client_register);
+EXPORT_SYMBOL_GPL(dma_release_channel);
/**
- * dma_async_client_unregister - unregister a client and free the &dma_client
- * @client: &dma_client to free
- *
- * Force frees any allocated DMA channels, frees the &dma_client memory
+ * dmaengine_get - register interest in dma_channels
*/
-void dma_async_client_unregister(struct dma_client *client)
+void dmaengine_get(void)
{
- struct dma_device *device;
+ struct dma_device *device, *_d;
struct dma_chan *chan;
- enum dma_state_client ack;
-
- if (!client)
- return;
+ int err;
mutex_lock(&dma_list_mutex);
- /* free all channels the client is holding */
- list_for_each_entry(device, &dma_device_list, global_node)
- list_for_each_entry(chan, &device->channels, device_node) {
- ack = client->event_callback(client, chan,
- DMA_RESOURCE_REMOVED);
+ dmaengine_ref_count++;
- if (ack == DMA_ACK) {
- dma_chan_put(chan);
- chan->client_count--;
- }
+ /* try to grab channels */
+ list_for_each_entry_safe(device, _d, &dma_device_list, global_node) {
+ if (dma_has_cap(DMA_PRIVATE, device->cap_mask))
+ continue;
+ list_for_each_entry(chan, &device->channels, device_node) {
+ err = dma_chan_get(chan);
+ if (err == -ENODEV) {
+ /* module removed before we could use it */
+ list_del_rcu(&device->global_node);
+ break;
+ } else if (err)
+ pr_err("dmaengine: failed to get %s: (%d)\n",
+ dma_chan_name(chan), err);
}
+ }
- list_del(&client->global_node);
+ /* if this is the first reference and there were channels
+ * waiting we need to rebalance to get those channels
+ * incorporated into the channel table
+ */
+ if (dmaengine_ref_count == 1)
+ dma_channel_rebalance();
mutex_unlock(&dma_list_mutex);
}
-EXPORT_SYMBOL(dma_async_client_unregister);
+EXPORT_SYMBOL(dmaengine_get);
/**
- * dma_async_client_chan_request - send all available channels to the
- * client that satisfy the capability mask
- * @client - requester
+ * dmaengine_put - let dma drivers be removed when ref_count == 0
*/
-void dma_async_client_chan_request(struct dma_client *client)
+void dmaengine_put(void)
{
+ struct dma_device *device;
+ struct dma_chan *chan;
+
mutex_lock(&dma_list_mutex);
- dma_client_chan_alloc(client);
+ dmaengine_ref_count--;
+ BUG_ON(dmaengine_ref_count < 0);
+ /* drop channel references */
+ list_for_each_entry(device, &dma_device_list, global_node) {
+ if (dma_has_cap(DMA_PRIVATE, device->cap_mask))
+ continue;
+ list_for_each_entry(chan, &device->channels, device_node)
+ dma_chan_put(chan);
+ }
mutex_unlock(&dma_list_mutex);
}
-EXPORT_SYMBOL(dma_async_client_chan_request);
+EXPORT_SYMBOL(dmaengine_put);
/**
* dma_async_device_register - registers DMA devices found
@@ -357,9 +612,9 @@ EXPORT_SYMBOL(dma_async_client_chan_request);
*/
int dma_async_device_register(struct dma_device *device)
{
- static int id;
int chancnt = 0, rc;
struct dma_chan* chan;
+ atomic_t *idr_ref;
if (!device)
return -ENODEV;
@@ -386,57 +641,83 @@ int dma_async_device_register(struct dma_device *device)
BUG_ON(!device->device_issue_pending);
BUG_ON(!device->dev);
- init_completion(&device->done);
- kref_init(&device->refcount);
-
+ idr_ref = kmalloc(sizeof(*idr_ref), GFP_KERNEL);
+ if (!idr_ref)
+ return -ENOMEM;
+ atomic_set(idr_ref, 0);
+ idr_retry:
+ if (!idr_pre_get(&dma_idr, GFP_KERNEL))
+ return -ENOMEM;
mutex_lock(&dma_list_mutex);
- device->dev_id = id++;
+ rc = idr_get_new(&dma_idr, NULL, &device->dev_id);
mutex_unlock(&dma_list_mutex);
+ if (rc == -EAGAIN)
+ goto idr_retry;
+ else if (rc != 0)
+ return rc;
/* represent channels in sysfs. Probably want devs too */
list_for_each_entry(chan, &device->channels, device_node) {
chan->local = alloc_percpu(typeof(*chan->local));
if (chan->local == NULL)
continue;
+ chan->dev = kzalloc(sizeof(*chan->dev), GFP_KERNEL);
+ if (chan->dev == NULL) {
+ free_percpu(chan->local);
+ continue;
+ }
chan->chan_id = chancnt++;
- chan->dev.class = &dma_devclass;
- chan->dev.parent = device->dev;
- dev_set_name(&chan->dev, "dma%dchan%d",
+ chan->dev->device.class = &dma_devclass;
+ chan->dev->device.parent = device->dev;
+ chan->dev->chan = chan;
+ chan->dev->idr_ref = idr_ref;
+ chan->dev->dev_id = device->dev_id;
+ atomic_inc(idr_ref);
+ dev_set_name(&chan->dev->device, "dma%dchan%d",
device->dev_id, chan->chan_id);
- rc = device_register(&chan->dev);
+ rc = device_register(&chan->dev->device);
if (rc) {
- chancnt--;
free_percpu(chan->local);
chan->local = NULL;
goto err_out;
}
-
- /* One for the channel, one of the class device */
- kref_get(&device->refcount);
- kref_get(&device->refcount);
- kref_init(&chan->refcount);
chan->client_count = 0;
- chan->slow_ref = 0;
- INIT_RCU_HEAD(&chan->rcu);
}
+ device->chancnt = chancnt;
mutex_lock(&dma_list_mutex);
- list_add_tail(&device->global_node, &dma_device_list);
+ /* take references on public channels */
+ if (dmaengine_ref_count && !dma_has_cap(DMA_PRIVATE, device->cap_mask))
+ list_for_each_entry(chan, &device->channels, device_node) {
+ /* if clients are already waiting for channels we need
+ * to take references on their behalf
+ */
+ if (dma_chan_get(chan) == -ENODEV) {
+ /* note we can only get here for the first
+ * channel as the remaining channels are
+ * guaranteed to get a reference
+ */
+ rc = -ENODEV;
+ mutex_unlock(&dma_list_mutex);
+ goto err_out;
+ }
+ }
+ list_add_tail_rcu(&device->global_node, &dma_device_list);
+ dma_channel_rebalance();
mutex_unlock(&dma_list_mutex);
- dma_clients_notify_available();
-
return 0;
err_out:
list_for_each_entry(chan, &device->channels, device_node) {
if (chan->local == NULL)
continue;
- kref_put(&device->refcount, dma_async_device_cleanup);
- device_unregister(&chan->dev);
- chancnt--;
+ mutex_lock(&dma_list_mutex);
+ chan->dev->chan = NULL;
+ mutex_unlock(&dma_list_mutex);
+ device_unregister(&chan->dev->device);
free_percpu(chan->local);
}
return rc;
@@ -444,37 +725,30 @@ err_out:
EXPORT_SYMBOL(dma_async_device_register);
/**
- * dma_async_device_cleanup - function called when all references are released
- * @kref: kernel reference object
- */
-static void dma_async_device_cleanup(struct kref *kref)
-{
- struct dma_device *device;
-
- device = container_of(kref, struct dma_device, refcount);
- complete(&device->done);
-}
-
-/**
- * dma_async_device_unregister - unregisters DMA devices
+ * dma_async_device_unregister - unregister a DMA device
* @device: &dma_device
+ *
+ * This routine is called by dma driver exit routines, dmaengine holds module
+ * references to prevent it being called while channels are in use.
*/
void dma_async_device_unregister(struct dma_device *device)
{
struct dma_chan *chan;
mutex_lock(&dma_list_mutex);
- list_del(&device->global_node);
+ list_del_rcu(&device->global_node);
+ dma_channel_rebalance();
mutex_unlock(&dma_list_mutex);
list_for_each_entry(chan, &device->channels, device_node) {
- dma_clients_notify_removed(chan);
- device_unregister(&chan->dev);
- dma_chan_release(chan);
+ WARN_ONCE(chan->client_count,
+ "%s called while %d clients hold a reference\n",
+ __func__, chan->client_count);
+ mutex_lock(&dma_list_mutex);
+ chan->dev->chan = NULL;
+ mutex_unlock(&dma_list_mutex);
+ device_unregister(&chan->dev->device);
}
-
- kref_put(&device->refcount, dma_async_device_cleanup);
- wait_for_completion(&device->done);
}
EXPORT_SYMBOL(dma_async_device_unregister);
@@ -626,10 +900,96 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
}
EXPORT_SYMBOL(dma_async_tx_descriptor_init);
+/* dma_wait_for_async_tx - spin wait for a transaction to complete
+ * @tx: in-flight transaction to wait on
+ *
+ * This routine assumes that tx was obtained from a call to async_memcpy,
+ * async_xor, async_memset, etc which ensures that tx is "in-flight" (prepped
+ * and submitted). Walking the parent chain is only meant to cover for DMA
+ * drivers that do not implement the DMA_INTERRUPT capability and may race with
+ * the driver's descriptor cleanup routine.
+ */
+enum dma_status
+dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx)
+{
+ enum dma_status status;
+ struct dma_async_tx_descriptor *iter;
+ struct dma_async_tx_descriptor *parent;
+
+ if (!tx)
+ return DMA_SUCCESS;
+
+ WARN_ONCE(tx->parent, "%s: speculatively walking dependency chain for"
+ " %s\n", __func__, dma_chan_name(tx->chan));
+
+ /* poll through the dependency chain, return when tx is complete */
+ do {
+ iter = tx;
+
+ /* find the root of the unsubmitted dependency chain */
+ do {
+ parent = iter->parent;
+ if (!parent)
+ break;
+ else
+ iter = parent;
+ } while (parent);
+
+ /* there is a small window for ->parent == NULL and
+ * ->cookie == -EBUSY
+ */
+ while (iter->cookie == -EBUSY)
+ cpu_relax();
+
+ status = dma_sync_wait(iter->chan, iter->cookie);
+ } while (status == DMA_IN_PROGRESS || (iter != tx));
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(dma_wait_for_async_tx);
+
+/* dma_run_dependencies - helper routine for dma drivers to process
+ * (start) dependent operations on their target channel
+ * @tx: transaction with dependencies
+ */
+void dma_run_dependencies(struct dma_async_tx_descriptor *tx)
+{
+ struct dma_async_tx_descriptor *dep = tx->next;
+ struct dma_async_tx_descriptor *dep_next;
+ struct dma_chan *chan;
+
+ if (!dep)
+ return;
+
+ chan = dep->chan;
+
+ /* keep submitting up until a channel switch is detected
+ * in that case we will be called again as a result of
+ * processing the interrupt from async_tx_channel_switch
+ */
+ for (; dep; dep = dep_next) {
+ spin_lock_bh(&dep->lock);
+ dep->parent = NULL;
+ dep_next = dep->next;
+ if (dep_next && dep_next->chan == chan)
+ dep->next = NULL; /* ->next will be submitted */
+ else
+ dep_next = NULL; /* submit current dep and terminate */
+ spin_unlock_bh(&dep->lock);
+
+ dep->tx_submit(dep);
+ }
+
+ chan->device->device_issue_pending(chan);
+}
+EXPORT_SYMBOL_GPL(dma_run_dependencies);
+
static int __init dma_bus_init(void)
{
+ idr_init(&dma_idr);
mutex_init(&dma_list_mutex);
return class_register(&dma_devclass);
}
-subsys_initcall(dma_bus_init);
+arch_initcall(dma_bus_init);
+
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index ed9636bfb54a..3603f1ea5b28 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -35,7 +35,7 @@ MODULE_PARM_DESC(threads_per_chan,
static unsigned int max_channels;
module_param(max_channels, uint, S_IRUGO);
-MODULE_PARM_DESC(nr_channels,
+MODULE_PARM_DESC(max_channels,
"Maximum number of channels to use (default: all)");
/*
@@ -71,7 +71,7 @@ struct dmatest_chan {
/*
* These are protected by dma_list_mutex since they're only used by
- * the DMA client event callback
+ * the DMA filter function callback
*/
static LIST_HEAD(dmatest_channels);
static unsigned int nr_channels;
@@ -80,7 +80,7 @@ static bool dmatest_match_channel(struct dma_chan *chan)
{
if (test_channel[0] == '\0')
return true;
- return strcmp(dev_name(&chan->dev), test_channel) == 0;
+ return strcmp(dma_chan_name(chan), test_channel) == 0;
}
static bool dmatest_match_device(struct dma_device *device)
@@ -215,7 +215,6 @@ static int dmatest_func(void *data)
smp_rmb();
chan = thread->chan;
- dma_chan_get(chan);
while (!kthread_should_stop()) {
total_tests++;
@@ -293,7 +292,6 @@ static int dmatest_func(void *data)
}
ret = 0;
- dma_chan_put(chan);
kfree(thread->dstbuf);
err_dstbuf:
kfree(thread->srcbuf);
@@ -319,21 +317,16 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc)
kfree(dtc);
}
-static enum dma_state_client dmatest_add_channel(struct dma_chan *chan)
+static int dmatest_add_channel(struct dma_chan *chan)
{
struct dmatest_chan *dtc;
struct dmatest_thread *thread;
unsigned int i;
- /* Have we already been told about this channel? */
- list_for_each_entry(dtc, &dmatest_channels, node)
- if (dtc->chan == chan)
- return DMA_DUP;
-
dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL);
if (!dtc) {
- pr_warning("dmatest: No memory for %s\n", dev_name(&chan->dev));
- return DMA_NAK;
+ pr_warning("dmatest: No memory for %s\n", dma_chan_name(chan));
+ return -ENOMEM;
}
dtc->chan = chan;
@@ -343,16 +336,16 @@ static enum dma_state_client dmatest_add_channel(struct dma_chan *chan)
thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL);
if (!thread) {
pr_warning("dmatest: No memory for %s-test%u\n",
- dev_name(&chan->dev), i);
+ dma_chan_name(chan), i);
break;
}
thread->chan = dtc->chan;
smp_wmb();
thread->task = kthread_run(dmatest_func, thread, "%s-test%u",
- dev_name(&chan->dev), i);
+ dma_chan_name(chan), i);
if (IS_ERR(thread->task)) {
pr_warning("dmatest: Failed to run thread %s-test%u\n",
- dev_name(&chan->dev), i);
+ dma_chan_name(chan), i);
kfree(thread);
break;
}
@@ -362,86 +355,62 @@ static enum dma_state_client dmatest_add_channel(struct dma_chan *chan)
list_add_tail(&thread->node, &dtc->threads);
}
- pr_info("dmatest: Started %u threads using %s\n", i, dev_name(&chan->dev));
+ pr_info("dmatest: Started %u threads using %s\n", i, dma_chan_name(chan));
list_add_tail(&dtc->node, &dmatest_channels);
nr_channels++;
- return DMA_ACK;
-}
-
-static enum dma_state_client dmatest_remove_channel(struct dma_chan *chan)
-{
- struct dmatest_chan *dtc, *_dtc;
-
- list_for_each_entry_safe(dtc, _dtc, &dmatest_channels, node) {
- if (dtc->chan == chan) {
- list_del(&dtc->node);
- dmatest_cleanup_channel(dtc);
- pr_debug("dmatest: lost channel %s\n",
- dev_name(&chan->dev));
- return DMA_ACK;
- }
- }
-
- return DMA_DUP;
+ return 0;
}
-/*
- * Start testing threads as new channels are assigned to us, and kill
- * them when the channels go away.
- *
- * When we unregister the client, all channels are removed so this
- * will also take care of cleaning things up when the module is
- * unloaded.
- */
-static enum dma_state_client
-dmatest_event(struct dma_client *client, struct dma_chan *chan,
- enum dma_state state)
+static bool filter(struct dma_chan *chan, void *param)
{
- enum dma_state_client ack = DMA_NAK;
-
- switch (state) {
- case DMA_RESOURCE_AVAILABLE:
- if (!dmatest_match_channel(chan)
- || !dmatest_match_device(chan->device))
- ack = DMA_DUP;
- else if (max_channels && nr_channels >= max_channels)
- ack = DMA_NAK;
- else
- ack = dmatest_add_channel(chan);
- break;
-
- case DMA_RESOURCE_REMOVED:
- ack = dmatest_remove_channel(chan);
- break;
-
- default:
- pr_info("dmatest: Unhandled event %u (%s)\n",
- state, dev_name(&chan->dev));
- break;
- }
-
- return ack;
+ if (!dmatest_match_channel(chan) || !dmatest_match_device(chan->device))
+ return false;
+ else
+ return true;
}
-static struct dma_client dmatest_client = {
- .event_callback = dmatest_event,
-};
-
static int __init dmatest_init(void)
{
- dma_cap_set(DMA_MEMCPY, dmatest_client.cap_mask);
- dma_async_client_register(&dmatest_client);
- dma_async_client_chan_request(&dmatest_client);
+ dma_cap_mask_t mask;
+ struct dma_chan *chan;
+ int err = 0;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_MEMCPY, mask);
+ for (;;) {
+ chan = dma_request_channel(mask, filter, NULL);
+ if (chan) {
+ err = dmatest_add_channel(chan);
+ if (err == 0)
+ continue;
+ else {
+ dma_release_channel(chan);
+ break; /* add_channel failed, punt */
+ }
+ } else
+ break; /* no more channels available */
+ if (max_channels && nr_channels >= max_channels)
+ break; /* we have all we need */
+ }
- return 0;
+ return err;
}
-module_init(dmatest_init);
+/* when compiled-in wait for drivers to load first */
+late_initcall(dmatest_init);
static void __exit dmatest_exit(void)
{
- dma_async_client_unregister(&dmatest_client);
+ struct dmatest_chan *dtc, *_dtc;
+
+ list_for_each_entry_safe(dtc, _dtc, &dmatest_channels, node) {
+ list_del(&dtc->node);
+ dmatest_cleanup_channel(dtc);
+ pr_debug("dmatest: dropped channel %s\n",
+ dma_chan_name(dtc->chan));
+ dma_release_channel(dtc->chan);
+ }
}
module_exit(dmatest_exit);
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 0778d99aea7c..6b702cc46b3d 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -70,6 +70,15 @@
* the controller, though.
*/
+static struct device *chan2dev(struct dma_chan *chan)
+{
+ return &chan->dev->device;
+}
+static struct device *chan2parent(struct dma_chan *chan)
+{
+ return chan->dev->device.parent;
+}
+
static struct dw_desc *dwc_first_active(struct dw_dma_chan *dwc)
{
return list_entry(dwc->active_list.next, struct dw_desc, desc_node);
@@ -93,12 +102,12 @@ static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc)
ret = desc;
break;
}
- dev_dbg(&dwc->chan.dev, "desc %p not ACKed\n", desc);
+ dev_dbg(chan2dev(&dwc->chan), "desc %p not ACKed\n", desc);
i++;
}
spin_unlock_bh(&dwc->lock);
- dev_vdbg(&dwc->chan.dev, "scanned %u descriptors on freelist\n", i);
+ dev_vdbg(chan2dev(&dwc->chan), "scanned %u descriptors on freelist\n", i);
return ret;
}
@@ -108,10 +117,10 @@ static void dwc_sync_desc_for_cpu(struct dw_dma_chan *dwc, struct dw_desc *desc)
struct dw_desc *child;
list_for_each_entry(child, &desc->txd.tx_list, desc_node)
- dma_sync_single_for_cpu(dwc->chan.dev.parent,
+ dma_sync_single_for_cpu(chan2parent(&dwc->chan),
child->txd.phys, sizeof(child->lli),
DMA_TO_DEVICE);
- dma_sync_single_for_cpu(dwc->chan.dev.parent,
+ dma_sync_single_for_cpu(chan2parent(&dwc->chan),
desc->txd.phys, sizeof(desc->lli),
DMA_TO_DEVICE);
}
@@ -129,11 +138,11 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc)
spin_lock_bh(&dwc->lock);
list_for_each_entry(child, &desc->txd.tx_list, desc_node)
- dev_vdbg(&dwc->chan.dev,
+ dev_vdbg(chan2dev(&dwc->chan),
"moving child desc %p to freelist\n",
child);
list_splice_init(&desc->txd.tx_list, &dwc->free_list);
- dev_vdbg(&dwc->chan.dev, "moving desc %p to freelist\n", desc);
+ dev_vdbg(chan2dev(&dwc->chan), "moving desc %p to freelist\n", desc);
list_add(&desc->desc_node, &dwc->free_list);
spin_unlock_bh(&dwc->lock);
}
@@ -163,9 +172,9 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
/* ASSERT: channel is idle */
if (dma_readl(dw, CH_EN) & dwc->mask) {
- dev_err(&dwc->chan.dev,
+ dev_err(chan2dev(&dwc->chan),
"BUG: Attempted to start non-idle channel\n");
- dev_err(&dwc->chan.dev,
+ dev_err(chan2dev(&dwc->chan),
" SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n",
channel_readl(dwc, SAR),
channel_readl(dwc, DAR),
@@ -193,7 +202,7 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc)
void *param;
struct dma_async_tx_descriptor *txd = &desc->txd;
- dev_vdbg(&dwc->chan.dev, "descriptor %u complete\n", txd->cookie);
+ dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie);
dwc->completed = txd->cookie;
callback = txd->callback;
@@ -208,11 +217,11 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc)
* mapped before they were submitted...
*/
if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP))
- dma_unmap_page(dwc->chan.dev.parent, desc->lli.dar, desc->len,
- DMA_FROM_DEVICE);
+ dma_unmap_page(chan2parent(&dwc->chan), desc->lli.dar,
+ desc->len, DMA_FROM_DEVICE);
if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP))
- dma_unmap_page(dwc->chan.dev.parent, desc->lli.sar, desc->len,
- DMA_TO_DEVICE);
+ dma_unmap_page(chan2parent(&dwc->chan), desc->lli.sar,
+ desc->len, DMA_TO_DEVICE);
/*
* The API requires that no submissions are done from a
@@ -228,7 +237,7 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
LIST_HEAD(list);
if (dma_readl(dw, CH_EN) & dwc->mask) {
- dev_err(&dwc->chan.dev,
+ dev_err(chan2dev(&dwc->chan),
"BUG: XFER bit set, but channel not idle!\n");
/* Try to continue after resetting the channel... */
@@ -273,7 +282,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
return;
}
- dev_vdbg(&dwc->chan.dev, "scan_descriptors: llp=0x%x\n", llp);
+ dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%x\n", llp);
list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
if (desc->lli.llp == llp)
@@ -292,7 +301,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
dwc_descriptor_complete(dwc, desc);
}
- dev_err(&dwc->chan.dev,
+ dev_err(chan2dev(&dwc->chan),
"BUG: All descriptors done, but channel not idle!\n");
/* Try to continue after resetting the channel... */
@@ -308,7 +317,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
static void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_lli *lli)
{
- dev_printk(KERN_CRIT, &dwc->chan.dev,
+ dev_printk(KERN_CRIT, chan2dev(&dwc->chan),
" desc: s0x%x d0x%x l0x%x c0x%x:%x\n",
lli->sar, lli->dar, lli->llp,
lli->ctlhi, lli->ctllo);
@@ -342,9 +351,9 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
* controller flagged an error instead of scribbling over
* random memory locations.
*/
- dev_printk(KERN_CRIT, &dwc->chan.dev,
+ dev_printk(KERN_CRIT, chan2dev(&dwc->chan),
"Bad descriptor submitted for DMA!\n");
- dev_printk(KERN_CRIT, &dwc->chan.dev,
+ dev_printk(KERN_CRIT, chan2dev(&dwc->chan),
" cookie: %d\n", bad_desc->txd.cookie);
dwc_dump_lli(dwc, &bad_desc->lli);
list_for_each_entry(child, &bad_desc->txd.tx_list, desc_node)
@@ -442,12 +451,12 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx)
* for DMA. But this is hard to do in a race-free manner.
*/
if (list_empty(&dwc->active_list)) {
- dev_vdbg(&tx->chan->dev, "tx_submit: started %u\n",
+ dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n",
desc->txd.cookie);
dwc_dostart(dwc, desc);
list_add_tail(&desc->desc_node, &dwc->active_list);
} else {
- dev_vdbg(&tx->chan->dev, "tx_submit: queued %u\n",
+ dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n",
desc->txd.cookie);
list_add_tail(&desc->desc_node, &dwc->queue);
@@ -472,11 +481,11 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
unsigned int dst_width;
u32 ctllo;
- dev_vdbg(&chan->dev, "prep_dma_memcpy d0x%x s0x%x l0x%zx f0x%lx\n",
+ dev_vdbg(chan2dev(chan), "prep_dma_memcpy d0x%x s0x%x l0x%zx f0x%lx\n",
dest, src, len, flags);
if (unlikely(!len)) {
- dev_dbg(&chan->dev, "prep_dma_memcpy: length is zero!\n");
+ dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
return NULL;
}
@@ -516,7 +525,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
first = desc;
} else {
prev->lli.llp = desc->txd.phys;
- dma_sync_single_for_device(chan->dev.parent,
+ dma_sync_single_for_device(chan2parent(chan),
prev->txd.phys, sizeof(prev->lli),
DMA_TO_DEVICE);
list_add_tail(&desc->desc_node,
@@ -531,7 +540,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
prev->lli.ctllo |= DWC_CTLL_INT_EN;
prev->lli.llp = 0;
- dma_sync_single_for_device(chan->dev.parent,
+ dma_sync_single_for_device(chan2parent(chan),
prev->txd.phys, sizeof(prev->lli),
DMA_TO_DEVICE);
@@ -562,15 +571,15 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
struct scatterlist *sg;
size_t total_len = 0;
- dev_vdbg(&chan->dev, "prep_dma_slave\n");
+ dev_vdbg(chan2dev(chan), "prep_dma_slave\n");
if (unlikely(!dws || !sg_len))
return NULL;
- reg_width = dws->slave.reg_width;
+ reg_width = dws->reg_width;
prev = first = NULL;
- sg_len = dma_map_sg(chan->dev.parent, sgl, sg_len, direction);
+ sg_len = dma_map_sg(chan2parent(chan), sgl, sg_len, direction);
switch (direction) {
case DMA_TO_DEVICE:
@@ -579,7 +588,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
| DWC_CTLL_DST_FIX
| DWC_CTLL_SRC_INC
| DWC_CTLL_FC_M2P);
- reg = dws->slave.tx_reg;
+ reg = dws->tx_reg;
for_each_sg(sgl, sg, sg_len, i) {
struct dw_desc *desc;
u32 len;
@@ -587,7 +596,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
desc = dwc_desc_get(dwc);
if (!desc) {
- dev_err(&chan->dev,
+ dev_err(chan2dev(chan),
"not enough descriptors available\n");
goto err_desc_get;
}
@@ -607,7 +616,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
first = desc;
} else {
prev->lli.llp = desc->txd.phys;
- dma_sync_single_for_device(chan->dev.parent,
+ dma_sync_single_for_device(chan2parent(chan),
prev->txd.phys,
sizeof(prev->lli),
DMA_TO_DEVICE);
@@ -625,7 +634,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
| DWC_CTLL_SRC_FIX
| DWC_CTLL_FC_P2M);
- reg = dws->slave.rx_reg;
+ reg = dws->rx_reg;
for_each_sg(sgl, sg, sg_len, i) {
struct dw_desc *desc;
u32 len;
@@ -633,7 +642,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
desc = dwc_desc_get(dwc);
if (!desc) {
- dev_err(&chan->dev,
+ dev_err(chan2dev(chan),
"not enough descriptors available\n");
goto err_desc_get;
}
@@ -653,7 +662,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
first = desc;
} else {
prev->lli.llp = desc->txd.phys;
- dma_sync_single_for_device(chan->dev.parent,
+ dma_sync_single_for_device(chan2parent(chan),
prev->txd.phys,
sizeof(prev->lli),
DMA_TO_DEVICE);
@@ -673,7 +682,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
prev->lli.ctllo |= DWC_CTLL_INT_EN;
prev->lli.llp = 0;
- dma_sync_single_for_device(chan->dev.parent,
+ dma_sync_single_for_device(chan2parent(chan),
prev->txd.phys, sizeof(prev->lli),
DMA_TO_DEVICE);
@@ -758,29 +767,21 @@ static void dwc_issue_pending(struct dma_chan *chan)
spin_unlock_bh(&dwc->lock);
}
-static int dwc_alloc_chan_resources(struct dma_chan *chan,
- struct dma_client *client)
+static int dwc_alloc_chan_resources(struct dma_chan *chan)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
struct dw_dma *dw = to_dw_dma(chan->device);
struct dw_desc *desc;
- struct dma_slave *slave;
struct dw_dma_slave *dws;
int i;
u32 cfghi;
u32 cfglo;
- dev_vdbg(&chan->dev, "alloc_chan_resources\n");
-
- /* Channels doing slave DMA can only handle one client. */
- if (dwc->dws || client->slave) {
- if (chan->client_count)
- return -EBUSY;
- }
+ dev_vdbg(chan2dev(chan), "alloc_chan_resources\n");
/* ASSERT: channel is idle */
if (dma_readl(dw, CH_EN) & dwc->mask) {
- dev_dbg(&chan->dev, "DMA channel not idle?\n");
+ dev_dbg(chan2dev(chan), "DMA channel not idle?\n");
return -EIO;
}
@@ -789,23 +790,17 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan,
cfghi = DWC_CFGH_FIFO_MODE;
cfglo = 0;
- slave = client->slave;
- if (slave) {
+ dws = dwc->dws;
+ if (dws) {
/*
* We need controller-specific data to set up slave
* transfers.
*/
- BUG_ON(!slave->dma_dev || slave->dma_dev != dw->dma.dev);
-
- dws = container_of(slave, struct dw_dma_slave, slave);
+ BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev);
- dwc->dws = dws;
cfghi = dws->cfg_hi;
cfglo = dws->cfg_lo;
- } else {
- dwc->dws = NULL;
}
-
channel_writel(dwc, CFG_LO, cfglo);
channel_writel(dwc, CFG_HI, cfghi);
@@ -822,7 +817,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan,
desc = kzalloc(sizeof(struct dw_desc), GFP_KERNEL);
if (!desc) {
- dev_info(&chan->dev,
+ dev_info(chan2dev(chan),
"only allocated %d descriptors\n", i);
spin_lock_bh(&dwc->lock);
break;
@@ -832,7 +827,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan,
desc->txd.tx_submit = dwc_tx_submit;
desc->txd.flags = DMA_CTRL_ACK;
INIT_LIST_HEAD(&desc->txd.tx_list);
- desc->txd.phys = dma_map_single(chan->dev.parent, &desc->lli,
+ desc->txd.phys = dma_map_single(chan2parent(chan), &desc->lli,
sizeof(desc->lli), DMA_TO_DEVICE);
dwc_desc_put(dwc, desc);
@@ -847,7 +842,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan,
spin_unlock_bh(&dwc->lock);
- dev_dbg(&chan->dev,
+ dev_dbg(chan2dev(chan),
"alloc_chan_resources allocated %d descriptors\n", i);
return i;
@@ -860,7 +855,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
struct dw_desc *desc, *_desc;
LIST_HEAD(list);
- dev_dbg(&chan->dev, "free_chan_resources (descs allocated=%u)\n",
+ dev_dbg(chan2dev(chan), "free_chan_resources (descs allocated=%u)\n",
dwc->descs_allocated);
/* ASSERT: channel is idle */
@@ -881,13 +876,13 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
spin_unlock_bh(&dwc->lock);
list_for_each_entry_safe(desc, _desc, &list, desc_node) {
- dev_vdbg(&chan->dev, " freeing descriptor %p\n", desc);
- dma_unmap_single(chan->dev.parent, desc->txd.phys,
+ dev_vdbg(chan2dev(chan), " freeing descriptor %p\n", desc);
+ dma_unmap_single(chan2parent(chan), desc->txd.phys,
sizeof(desc->lli), DMA_TO_DEVICE);
kfree(desc);
}
- dev_vdbg(&chan->dev, "free_chan_resources done\n");
+ dev_vdbg(chan2dev(chan), "free_chan_resources done\n");
}
/*----------------------------------------------------------------------*/
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 0b95dcce447e..ca70a21afc68 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -366,8 +366,7 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor(
*
* Return - The number of descriptors allocated.
*/
-static int fsl_dma_alloc_chan_resources(struct dma_chan *chan,
- struct dma_client *client)
+static int fsl_dma_alloc_chan_resources(struct dma_chan *chan)
{
struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan);
@@ -823,7 +822,7 @@ static int __devinit fsl_dma_chan_probe(struct fsl_dma_device *fdev,
*/
WARN_ON(fdev->feature != new_fsl_chan->feature);
- new_fsl_chan->dev = &new_fsl_chan->common.dev;
+ new_fsl_chan->dev = &new_fsl_chan->common.dev->device;
new_fsl_chan->reg_base = ioremap(new_fsl_chan->reg.start,
new_fsl_chan->reg.end - new_fsl_chan->reg.start + 1);
diff --git a/drivers/dma/ioat.c b/drivers/dma/ioat.c
index 9b16a3af9a0a..4105d6575b64 100644
--- a/drivers/dma/ioat.c
+++ b/drivers/dma/ioat.c
@@ -75,60 +75,10 @@ static int ioat_dca_enabled = 1;
module_param(ioat_dca_enabled, int, 0644);
MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)");
-static int ioat_setup_functionality(struct pci_dev *pdev, void __iomem *iobase)
-{
- struct ioat_device *device = pci_get_drvdata(pdev);
- u8 version;
- int err = 0;
-
- version = readb(iobase + IOAT_VER_OFFSET);
- switch (version) {
- case IOAT_VER_1_2:
- device->dma = ioat_dma_probe(pdev, iobase);
- if (device->dma && ioat_dca_enabled)
- device->dca = ioat_dca_init(pdev, iobase);
- break;
- case IOAT_VER_2_0:
- device->dma = ioat_dma_probe(pdev, iobase);
- if (device->dma && ioat_dca_enabled)
- device->dca = ioat2_dca_init(pdev, iobase);
- break;
- case IOAT_VER_3_0:
- device->dma = ioat_dma_probe(pdev, iobase);
- if (device->dma && ioat_dca_enabled)
- device->dca = ioat3_dca_init(pdev, iobase);
- break;
- default:
- err = -ENODEV;
- break;
- }
- if (!device->dma)
- err = -ENODEV;
- return err;
-}
-
-static void ioat_shutdown_functionality(struct pci_dev *pdev)
-{
- struct ioat_device *device = pci_get_drvdata(pdev);
-
- dev_err(&pdev->dev, "Removing dma and dca services\n");
- if (device->dca) {
- unregister_dca_provider(device->dca);
- free_dca_provider(device->dca);
- device->dca = NULL;
- }
-
- if (device->dma) {
- ioat_dma_remove(device->dma);
- device->dma = NULL;
- }
-}
-
static struct pci_driver ioat_pci_driver = {
.name = "ioatdma",
.id_table = ioat_pci_tbl,
.probe = ioat_probe,
- .shutdown = ioat_shutdown_functionality,
.remove = __devexit_p(ioat_remove),
};
@@ -179,7 +129,29 @@ static int __devinit ioat_probe(struct pci_dev *pdev,
pci_set_master(pdev);
- err = ioat_setup_functionality(pdev, iobase);
+ switch (readb(iobase + IOAT_VER_OFFSET)) {
+ case IOAT_VER_1_2:
+ device->dma = ioat_dma_probe(pdev, iobase);
+ if (device->dma && ioat_dca_enabled)
+ device->dca = ioat_dca_init(pdev, iobase);
+ break;
+ case IOAT_VER_2_0:
+ device->dma = ioat_dma_probe(pdev, iobase);
+ if (device->dma && ioat_dca_enabled)
+ device->dca = ioat2_dca_init(pdev, iobase);
+ break;
+ case IOAT_VER_3_0:
+ device->dma = ioat_dma_probe(pdev, iobase);
+ if (device->dma && ioat_dca_enabled)
+ device->dca = ioat3_dca_init(pdev, iobase);
+ break;
+ default:
+ err = -ENODEV;
+ break;
+ }
+ if (!device->dma)
+ err = -ENODEV;
+
if (err)
goto err_version;
@@ -198,17 +170,21 @@ err_enable_device:
return err;
}
-/*
- * It is unsafe to remove this module: if removed while a requested
- * dma is outstanding, esp. from tcp, it is possible to hang while
- * waiting for something that will never finish. However, if you're
- * feeling lucky, this usually works just fine.
- */
static void __devexit ioat_remove(struct pci_dev *pdev)
{
struct ioat_device *device = pci_get_drvdata(pdev);
- ioat_shutdown_functionality(pdev);
+ dev_err(&pdev->dev, "Removing dma and dca services\n");
+ if (device->dca) {
+ unregister_dca_provider(device->dca);
+ free_dca_provider(device->dca);
+ device->dca = NULL;
+ }
+
+ if (device->dma) {
+ ioat_dma_remove(device->dma);
+ device->dma = NULL;
+ }
kfree(device);
}
diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c
index 6607fdd00b1c..b3759c4b6536 100644
--- a/drivers/dma/ioat_dma.c
+++ b/drivers/dma/ioat_dma.c
@@ -734,8 +734,7 @@ static void ioat2_dma_massage_chan_desc(struct ioat_dma_chan *ioat_chan)
* ioat_dma_alloc_chan_resources - returns the number of allocated descriptors
* @chan: the channel to be filled out
*/
-static int ioat_dma_alloc_chan_resources(struct dma_chan *chan,
- struct dma_client *client)
+static int ioat_dma_alloc_chan_resources(struct dma_chan *chan)
{
struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
struct ioat_desc_sw *desc;
@@ -1341,12 +1340,11 @@ static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan)
*/
#define IOAT_TEST_SIZE 2000
-DECLARE_COMPLETION(test_completion);
static void ioat_dma_test_callback(void *dma_async_param)
{
- printk(KERN_ERR "ioatdma: ioat_dma_test_callback(%p)\n",
- dma_async_param);
- complete(&test_completion);
+ struct completion *cmp = dma_async_param;
+
+ complete(cmp);
}
/**
@@ -1363,6 +1361,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
dma_addr_t dma_dest, dma_src;
dma_cookie_t cookie;
int err = 0;
+ struct completion cmp;
src = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL);
if (!src)
@@ -1381,7 +1380,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
dma_chan = container_of(device->common.channels.next,
struct dma_chan,
device_node);
- if (device->common.device_alloc_chan_resources(dma_chan, NULL) < 1) {
+ if (device->common.device_alloc_chan_resources(dma_chan) < 1) {
dev_err(&device->pdev->dev,
"selftest cannot allocate chan resource\n");
err = -ENODEV;
@@ -1402,8 +1401,9 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
}
async_tx_ack(tx);
+ init_completion(&cmp);
tx->callback = ioat_dma_test_callback;
- tx->callback_param = (void *)0x8086;
+ tx->callback_param = &cmp;
cookie = tx->tx_submit(tx);
if (cookie < 0) {
dev_err(&device->pdev->dev,
@@ -1413,7 +1413,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
}
device->common.device_issue_pending(dma_chan);
- wait_for_completion_timeout(&test_completion, msecs_to_jiffies(3000));
+ wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
if (device->common.device_is_tx_complete(dma_chan, cookie, NULL, NULL)
!= DMA_SUCCESS) {
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
index 6be317262200..ea5440dd10dc 100644
--- a/drivers/dma/iop-adma.c
+++ b/drivers/dma/iop-adma.c
@@ -24,7 +24,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/async_tx.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
@@ -116,7 +115,7 @@ iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc,
}
/* run dependent operations */
- async_tx_run_dependencies(&desc->async_tx);
+ dma_run_dependencies(&desc->async_tx);
return cookie;
}
@@ -270,8 +269,6 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan)
break;
}
- BUG_ON(!seen_current);
-
if (cookie > 0) {
iop_chan->completed_cookie = cookie;
pr_debug("\tcompleted cookie %d\n", cookie);
@@ -471,8 +468,7 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan);
* greater than 2x the number slots needed to satisfy a device->max_xor
* request.
* */
-static int iop_adma_alloc_chan_resources(struct dma_chan *chan,
- struct dma_client *client)
+static int iop_adma_alloc_chan_resources(struct dma_chan *chan)
{
char *hw_desc;
int idx;
@@ -866,7 +862,7 @@ static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device)
dma_chan = container_of(device->common.channels.next,
struct dma_chan,
device_node);
- if (iop_adma_alloc_chan_resources(dma_chan, NULL) < 1) {
+ if (iop_adma_alloc_chan_resources(dma_chan) < 1) {
err = -ENODEV;
goto out;
}
@@ -964,7 +960,7 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
dma_chan = container_of(device->common.channels.next,
struct dma_chan,
device_node);
- if (iop_adma_alloc_chan_resources(dma_chan, NULL) < 1) {
+ if (iop_adma_alloc_chan_resources(dma_chan) < 1) {
err = -ENODEV;
goto out;
}
@@ -1115,26 +1111,13 @@ static int __devexit iop_adma_remove(struct platform_device *dev)
struct iop_adma_device *device = platform_get_drvdata(dev);
struct dma_chan *chan, *_chan;
struct iop_adma_chan *iop_chan;
- int i;
struct iop_adma_platform_data *plat_data = dev->dev.platform_data;
dma_async_device_unregister(&device->common);
- for (i = 0; i < 3; i++) {
- unsigned int irq;
- irq = platform_get_irq(dev, i);
- free_irq(irq, device);
- }
-
dma_free_coherent(&dev->dev, plat_data->pool_size,
device->dma_desc_pool_virt, device->dma_desc_pool);
- do {
- struct resource *res;
- res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, res->end - res->start);
- } while (0);
-
list_for_each_entry_safe(chan, _chan, &device->common.channels,
device_node) {
iop_chan = to_iop_adma_chan(chan);
@@ -1255,7 +1238,6 @@ static int __devinit iop_adma_probe(struct platform_device *pdev)
spin_lock_init(&iop_chan->lock);
INIT_LIST_HEAD(&iop_chan->chain);
INIT_LIST_HEAD(&iop_chan->all_slots);
- INIT_RCU_HEAD(&iop_chan->common.rcu);
iop_chan->common.device = dma_dev;
list_add_tail(&iop_chan->common.device_node, &dma_dev->channels);
@@ -1431,16 +1413,12 @@ static int __init iop_adma_init (void)
return platform_driver_register(&iop_adma_driver);
}
-/* it's currently unsafe to unload this module */
-#if 0
static void __exit iop_adma_exit (void)
{
platform_driver_unregister(&iop_adma_driver);
return;
}
module_exit(iop_adma_exit);
-#endif
-
module_init(iop_adma_init);
MODULE_AUTHOR("Intel Corporation");
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index bcda17426411..d35cbd1ff0b3 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -18,7 +18,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/async_tx.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
@@ -340,7 +339,7 @@ mv_xor_run_tx_complete_actions(struct mv_xor_desc_slot *desc,
}
/* run dependent operations */
- async_tx_run_dependencies(&desc->async_tx);
+ dma_run_dependencies(&desc->async_tx);
return cookie;
}
@@ -607,8 +606,7 @@ submit_done:
}
/* returns the number of allocated descriptors */
-static int mv_xor_alloc_chan_resources(struct dma_chan *chan,
- struct dma_client *client)
+static int mv_xor_alloc_chan_resources(struct dma_chan *chan)
{
char *hw_desc;
int idx;
@@ -958,7 +956,7 @@ static int __devinit mv_xor_memcpy_self_test(struct mv_xor_device *device)
dma_chan = container_of(device->common.channels.next,
struct dma_chan,
device_node);
- if (mv_xor_alloc_chan_resources(dma_chan, NULL) < 1) {
+ if (mv_xor_alloc_chan_resources(dma_chan) < 1) {
err = -ENODEV;
goto out;
}
@@ -1053,7 +1051,7 @@ mv_xor_xor_self_test(struct mv_xor_device *device)
dma_chan = container_of(device->common.channels.next,
struct dma_chan,
device_node);
- if (mv_xor_alloc_chan_resources(dma_chan, NULL) < 1) {
+ if (mv_xor_alloc_chan_resources(dma_chan) < 1) {
err = -ENODEV;
goto out;
}
@@ -1221,7 +1219,6 @@ static int __devinit mv_xor_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&mv_chan->chain);
INIT_LIST_HEAD(&mv_chan->completed_slots);
INIT_LIST_HEAD(&mv_chan->all_slots);
- INIT_RCU_HEAD(&mv_chan->common.rcu);
mv_chan->common.device = dma_dev;
list_add_tail(&mv_chan->common.device_node, &dma_dev->channels);
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c
index 418c18f07e9d..6bd91a15d5e6 100644
--- a/drivers/firewire/fw-card.c
+++ b/drivers/firewire/fw-card.c
@@ -75,7 +75,7 @@ generate_config_rom(struct fw_card *card, size_t *config_rom_length)
* controller, block reads to the config rom accesses the host
* memory, but quadlet read access the hardware bus info block
* registers. That's just crack, but it means we should make
- * sure the contents of bus info block in host memory mathces
+ * sure the contents of bus info block in host memory matches
* the version stored in the OHCI registers.
*/
@@ -189,6 +189,17 @@ static const char gap_count_table[] = {
63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40
};
+void
+fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
+{
+ int scheduled;
+
+ fw_card_get(card);
+ scheduled = schedule_delayed_work(&card->work, delay);
+ if (!scheduled)
+ fw_card_put(card);
+}
+
static void
fw_card_bm_work(struct work_struct *work)
{
@@ -198,6 +209,8 @@ fw_card_bm_work(struct work_struct *work)
unsigned long flags;
int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode;
bool do_reset = false;
+ bool root_device_is_running;
+ bool root_device_is_cmc;
__be32 lock_data[2];
spin_lock_irqsave(&card->lock, flags);
@@ -206,15 +219,16 @@ fw_card_bm_work(struct work_struct *work)
if (local_node == NULL) {
spin_unlock_irqrestore(&card->lock, flags);
- return;
+ goto out_put_card;
}
fw_node_get(local_node);
fw_node_get(root_node);
generation = card->generation;
root_device = root_node->data;
- if (root_device)
- fw_device_get(root_device);
+ root_device_is_running = root_device &&
+ atomic_read(&root_device->state) == FW_DEVICE_RUNNING;
+ root_device_is_cmc = root_device && root_device->cmc;
root_id = root_node->node_id;
grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10));
@@ -280,7 +294,7 @@ fw_card_bm_work(struct work_struct *work)
* this task 100ms from now.
*/
spin_unlock_irqrestore(&card->lock, flags);
- schedule_delayed_work(&card->work, DIV_ROUND_UP(HZ, 10));
+ fw_schedule_bm_work(card, DIV_ROUND_UP(HZ, 10));
goto out;
}
@@ -297,14 +311,14 @@ fw_card_bm_work(struct work_struct *work)
* config rom. In either case, pick another root.
*/
new_root_id = local_node->node_id;
- } else if (atomic_read(&root_device->state) != FW_DEVICE_RUNNING) {
+ } else if (!root_device_is_running) {
/*
* If we haven't probed this device yet, bail out now
* and let's try again once that's done.
*/
spin_unlock_irqrestore(&card->lock, flags);
goto out;
- } else if (root_device->cmc) {
+ } else if (root_device_is_cmc) {
/*
* FIXME: I suppose we should set the cmstr bit in the
* STATE_CLEAR register of this node, as described in
@@ -351,10 +365,10 @@ fw_card_bm_work(struct work_struct *work)
fw_core_initiate_bus_reset(card, 1);
}
out:
- if (root_device)
- fw_device_put(root_device);
fw_node_put(root_node);
fw_node_put(local_node);
+ out_put_card:
+ fw_card_put(card);
}
static void
@@ -510,7 +524,6 @@ fw_core_remove_card(struct fw_card *card)
fw_card_put(card);
wait_for_completion(&card->done);
- cancel_delayed_work_sync(&card->work);
WARN_ON(!list_empty(&card->transaction_list));
del_timer_sync(&card->flush_timer);
}
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index 6b9be42c7b98..2af5a8d1e012 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -159,7 +159,8 @@ static void fw_device_release(struct device *dev)
/*
* Take the card lock so we don't set this to NULL while a
- * FW_NODE_UPDATED callback is being handled.
+ * FW_NODE_UPDATED callback is being handled or while the
+ * bus manager work looks at this node.
*/
spin_lock_irqsave(&card->lock, flags);
device->node->data = NULL;
@@ -617,7 +618,7 @@ static int shutdown_unit(struct device *device, void *data)
*/
DECLARE_RWSEM(fw_device_rwsem);
-static DEFINE_IDR(fw_device_idr);
+DEFINE_IDR(fw_device_idr);
int fw_cdev_major;
struct fw_device *fw_device_get_by_devt(dev_t devt)
@@ -689,18 +690,19 @@ static void fw_device_init(struct work_struct *work)
fw_notify("giving up on config rom for node id %x\n",
device->node_id);
if (device->node == device->card->root_node)
- schedule_delayed_work(&device->card->work, 0);
+ fw_schedule_bm_work(device->card, 0);
fw_device_release(&device->device);
}
return;
}
- err = -ENOMEM;
+ device_initialize(&device->device);
fw_device_get(device);
down_write(&fw_device_rwsem);
- if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
- err = idr_get_new(&fw_device_idr, device, &minor);
+ err = idr_pre_get(&fw_device_idr, GFP_KERNEL) ?
+ idr_get_new(&fw_device_idr, device, &minor) :
+ -ENOMEM;
up_write(&fw_device_rwsem);
if (err < 0)
@@ -758,7 +760,7 @@ static void fw_device_init(struct work_struct *work)
* pretty harmless.
*/
if (device->node == device->card->root_node)
- schedule_delayed_work(&device->card->work, 0);
+ fw_schedule_bm_work(device->card, 0);
return;
@@ -892,7 +894,7 @@ static void fw_device_refresh(struct work_struct *work)
fw_device_shutdown(work);
out:
if (node_id == card->root_node->node_id)
- schedule_delayed_work(&card->work, 0);
+ fw_schedule_bm_work(card, 0);
}
void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
@@ -911,13 +913,14 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
/*
* Do minimal intialization of the device here, the
- * rest will happen in fw_device_init(). We need the
- * card and node so we can read the config rom and we
- * need to do device_initialize() now so
- * device_for_each_child() in FW_NODE_UPDATED is
- * doesn't freak out.
+ * rest will happen in fw_device_init().
+ *
+ * Attention: A lot of things, even fw_device_get(),
+ * cannot be done before fw_device_init() finished!
+ * You can basically just check device->state and
+ * schedule work until then, but only while holding
+ * card->lock.
*/
- device_initialize(&device->device);
atomic_set(&device->state, FW_DEVICE_INITIALIZING);
device->card = fw_card_get(card);
device->node = fw_node_get(node);
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h
index 42305bbac72f..df51732608d9 100644
--- a/drivers/firewire/fw-device.h
+++ b/drivers/firewire/fw-device.h
@@ -21,6 +21,7 @@
#include <linux/fs.h>
#include <linux/cdev.h>
+#include <linux/idr.h>
#include <linux/rwsem.h>
#include <asm/atomic.h>
@@ -99,6 +100,7 @@ void fw_device_cdev_update(struct fw_device *device);
void fw_device_cdev_remove(struct fw_device *device);
extern struct rw_semaphore fw_device_rwsem;
+extern struct idr fw_device_idr;
extern int fw_cdev_major;
/*
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index e54403ee59e7..e88d5067448c 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -670,17 +670,6 @@ static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu)
&d, sizeof(d), complete_agent_reset_write_no_wait, t);
}
-static void sbp2_set_generation(struct sbp2_logical_unit *lu, int generation)
-{
- struct fw_card *card = fw_device(lu->tgt->unit->device.parent)->card;
- unsigned long flags;
-
- /* serialize with comparisons of lu->generation and card->generation */
- spin_lock_irqsave(&card->lock, flags);
- lu->generation = generation;
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
static inline void sbp2_allow_block(struct sbp2_logical_unit *lu)
{
/*
@@ -884,7 +873,7 @@ static void sbp2_login(struct work_struct *work)
goto out;
generation = device->generation;
- smp_rmb(); /* node_id must not be older than generation */
+ smp_rmb(); /* node IDs must not be older than generation */
node_id = device->node_id;
local_node_id = device->card->node_id;
@@ -908,7 +897,8 @@ static void sbp2_login(struct work_struct *work)
tgt->node_id = node_id;
tgt->address_high = local_node_id << 16;
- sbp2_set_generation(lu, generation);
+ smp_wmb(); /* node IDs must not be older than generation */
+ lu->generation = generation;
lu->command_block_agent_address =
((u64)(be32_to_cpu(response.command_block_agent.high) & 0xffff)
@@ -1201,7 +1191,7 @@ static void sbp2_reconnect(struct work_struct *work)
goto out;
generation = device->generation;
- smp_rmb(); /* node_id must not be older than generation */
+ smp_rmb(); /* node IDs must not be older than generation */
node_id = device->node_id;
local_node_id = device->card->node_id;
@@ -1228,7 +1218,8 @@ static void sbp2_reconnect(struct work_struct *work)
tgt->node_id = node_id;
tgt->address_high = local_node_id << 16;
- sbp2_set_generation(lu, generation);
+ smp_wmb(); /* node IDs must not be older than generation */
+ lu->generation = generation;
fw_notify("%s: reconnected to LUN %04x (%d retries)\n",
tgt->bus_id, lu->lun, lu->retries);
diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c
index 5e204713002d..c9be6e6948c4 100644
--- a/drivers/firewire/fw-topology.c
+++ b/drivers/firewire/fw-topology.c
@@ -355,6 +355,9 @@ report_lost_node(struct fw_card *card,
{
fw_node_event(card, node, FW_NODE_DESTROYED);
fw_node_put(node);
+
+ /* Topology has changed - reset bus manager retry counter */
+ card->bm_retries = 0;
}
static void
@@ -374,6 +377,9 @@ report_found_node(struct fw_card *card,
}
fw_node_event(card, node, FW_NODE_CREATED);
+
+ /* Topology has changed - reset bus manager retry counter */
+ card->bm_retries = 0;
}
void fw_destroy_nodes(struct fw_card *card)
@@ -514,14 +520,6 @@ fw_core_handle_bus_reset(struct fw_card *card,
spin_lock_irqsave(&card->lock, flags);
- /*
- * If the new topology has a different self_id_count the topology
- * changed, either nodes were added or removed. In that case we
- * reset the IRM reset counter.
- */
- if (card->self_id_count != self_id_count)
- card->bm_retries = 0;
-
card->node_id = node_id;
/*
* Update node_id before generation to prevent anybody from using
@@ -530,7 +528,7 @@ fw_core_handle_bus_reset(struct fw_card *card,
smp_wmb();
card->generation = generation;
card->reset_jiffies = jiffies;
- schedule_delayed_work(&card->work, 0);
+ fw_schedule_bm_work(card, 0);
local_node = build_tree(card, self_ids, self_id_count);
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
index 2884f876397b..699ac041f39a 100644
--- a/drivers/firewire/fw-transaction.c
+++ b/drivers/firewire/fw-transaction.c
@@ -19,6 +19,7 @@
*/
#include <linux/completion.h>
+#include <linux/idr.h>
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/module.h>
@@ -971,6 +972,7 @@ static void __exit fw_core_cleanup(void)
{
unregister_chrdev(fw_cdev_major, "firewire");
bus_unregister(&fw_bus_type);
+ idr_destroy(&fw_device_idr);
}
module_init(fw_core_init);
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h
index 839466f0a795..c9ab12a15f6e 100644
--- a/drivers/firewire/fw-transaction.h
+++ b/drivers/firewire/fw-transaction.h
@@ -237,14 +237,6 @@ struct fw_card {
int link_speed;
int config_rom_generation;
- /*
- * We need to store up to 4 self ID for a maximum of 63
- * devices plus 3 words for the topology map header.
- */
- int self_id_count;
- u32 topology_map[252 + 3];
- u32 broadcast_channel;
-
spinlock_t lock; /* Take this lock when handling the lists in
* this struct. */
struct fw_node *local_node;
@@ -262,6 +254,9 @@ struct fw_card {
struct delayed_work work;
int bm_retries;
int bm_generation;
+
+ u32 broadcast_channel;
+ u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
};
static inline struct fw_card *fw_card_get(struct fw_card *card)
@@ -278,6 +273,8 @@ static inline void fw_card_put(struct fw_card *card)
kref_put(&card->kref, fw_card_release);
}
+extern void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
+
/*
* The iso packet format allows for an immediate header/payload part
* stored in 'header' immediately after the packet info plus an
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index 50a071f1c945..777fba48d2d3 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -238,11 +238,11 @@ static ssize_t host_control_on_shutdown_store(struct device *dev,
}
/**
- * smi_request: generate SMI request
+ * dcdbas_smi_request: generate SMI request
*
* Called with smi_data_lock.
*/
-static int smi_request(struct smi_cmd *smi_cmd)
+int dcdbas_smi_request(struct smi_cmd *smi_cmd)
{
cpumask_t old_mask;
int ret = 0;
@@ -309,14 +309,14 @@ static ssize_t smi_request_store(struct device *dev,
switch (val) {
case 2:
/* Raw SMI */
- ret = smi_request(smi_cmd);
+ ret = dcdbas_smi_request(smi_cmd);
if (!ret)
ret = count;
break;
case 1:
/* Calling Interface SMI */
smi_cmd->ebx = (u32) virt_to_phys(smi_cmd->command_buffer);
- ret = smi_request(smi_cmd);
+ ret = dcdbas_smi_request(smi_cmd);
if (!ret)
ret = count;
break;
@@ -333,6 +333,7 @@ out:
mutex_unlock(&smi_data_lock);
return ret;
}
+EXPORT_SYMBOL(dcdbas_smi_request);
/**
* host_control_smi: generate host control SMI
diff --git a/drivers/firmware/dcdbas.h b/drivers/firmware/dcdbas.h
index 87bc3417de27..ca3cb0a54ab6 100644
--- a/drivers/firmware/dcdbas.h
+++ b/drivers/firmware/dcdbas.h
@@ -101,5 +101,7 @@ struct apm_cmd {
} __attribute__ ((packed)) parameters;
} __attribute__ ((packed));
+int dcdbas_smi_request(struct smi_cmd *smi_cmd);
+
#endif /* _DCDBAS_H_ */
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
index 13946ebd77d6..b4704e150b28 100644
--- a/drivers/firmware/dell_rbu.c
+++ b/drivers/firmware/dell_rbu.c
@@ -576,7 +576,7 @@ static ssize_t read_rbu_image_type(struct kobject *kobj,
{
int size = 0;
if (!pos)
- size = sprintf(buffer, "%s\n", image_type);
+ size = scnprintf(buffer, count, "%s\n", image_type);
return size;
}
@@ -648,7 +648,7 @@ static ssize_t read_rbu_packet_size(struct kobject *kobj,
int size = 0;
if (!pos) {
spin_lock(&rbu_data.lock);
- size = sprintf(buffer, "%lu\n", rbu_data.packetsize);
+ size = scnprintf(buffer, count, "%lu\n", rbu_data.packetsize);
spin_unlock(&rbu_data.lock);
}
return size;
diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c
index 3bf8ee120d42..261b9aa3f248 100644
--- a/drivers/firmware/memmap.c
+++ b/drivers/firmware/memmap.c
@@ -56,9 +56,9 @@ struct memmap_attribute {
ssize_t (*show)(struct firmware_map_entry *entry, char *buf);
};
-struct memmap_attribute memmap_start_attr = __ATTR_RO(start);
-struct memmap_attribute memmap_end_attr = __ATTR_RO(end);
-struct memmap_attribute memmap_type_attr = __ATTR_RO(type);
+static struct memmap_attribute memmap_start_attr = __ATTR_RO(start);
+static struct memmap_attribute memmap_end_attr = __ATTR_RO(end);
+static struct memmap_attribute memmap_type_attr = __ATTR_RO(type);
/*
* These are default attributes that are added for every memmap entry.
diff --git a/drivers/gpio/max7301.c b/drivers/gpio/max7301.c
index 8b24d784db93..3e7f4e06386e 100644
--- a/drivers/gpio/max7301.c
+++ b/drivers/gpio/max7301.c
@@ -217,8 +217,10 @@ static int __devinit max7301_probe(struct spi_device *spi)
int i, ret;
pdata = spi->dev.platform_data;
- if (!pdata || !pdata->base)
- return -ENODEV;
+ if (!pdata || !pdata->base) {
+ dev_dbg(&spi->dev, "incorrect or missing platform data\n");
+ return -EINVAL;
+ }
/*
* bits_per_word cannot be configured in platform data
diff --git a/drivers/gpio/max732x.c b/drivers/gpio/max732x.c
index 55ae9a41897a..f7868243af89 100644
--- a/drivers/gpio/max732x.c
+++ b/drivers/gpio/max732x.c
@@ -267,8 +267,10 @@ static int __devinit max732x_probe(struct i2c_client *client,
int ret, nr_port;
pdata = client->dev.platform_data;
- if (pdata == NULL)
- return -ENODEV;
+ if (pdata == NULL) {
+ dev_dbg(&client->dev, "no platform data\n");
+ return -EINVAL;
+ }
chip = kzalloc(sizeof(struct max732x_chip), GFP_KERNEL);
if (chip == NULL)
diff --git a/drivers/gpio/mcp23s08.c b/drivers/gpio/mcp23s08.c
index 89c1d222e9d1..f6fae0e50e65 100644
--- a/drivers/gpio/mcp23s08.c
+++ b/drivers/gpio/mcp23s08.c
@@ -310,8 +310,10 @@ static int mcp23s08_probe(struct spi_device *spi)
unsigned base;
pdata = spi->dev.platform_data;
- if (!pdata || !gpio_is_valid(pdata->base))
- return -ENODEV;
+ if (!pdata || !gpio_is_valid(pdata->base)) {
+ dev_dbg(&spi->dev, "invalid or missing platform data\n");
+ return -EINVAL;
+ }
for (addr = 0; addr < 4; addr++) {
if (!pdata->chip[addr].is_present)
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 37f35388a2ae..8dc0164bd51e 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -202,8 +202,10 @@ static int __devinit pca953x_probe(struct i2c_client *client,
int ret;
pdata = client->dev.platform_data;
- if (pdata == NULL)
- return -ENODEV;
+ if (pdata == NULL) {
+ dev_dbg(&client->dev, "no platform data\n");
+ return -EINVAL;
+ }
chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
if (chip == NULL)
diff --git a/drivers/gpio/pcf857x.c b/drivers/gpio/pcf857x.c
index 4bc2070dd4a1..9525724be731 100644
--- a/drivers/gpio/pcf857x.c
+++ b/drivers/gpio/pcf857x.c
@@ -188,8 +188,10 @@ static int pcf857x_probe(struct i2c_client *client,
int status;
pdata = client->dev.platform_data;
- if (!pdata)
- return -ENODEV;
+ if (!pdata) {
+ dev_dbg(&client->dev, "no platform data\n");
+ return -EINVAL;
+ }
/* Allocate, initialize, and register this gpio_chip. */
gpio = kzalloc(sizeof *gpio, GFP_KERNEL);
@@ -248,8 +250,10 @@ static int pcf857x_probe(struct i2c_client *client,
else
status = i2c_read_le16(client);
- } else
- status = -ENODEV;
+ } else {
+ dev_dbg(&client->dev, "unsupported number of gpios\n");
+ status = -EINVAL;
+ }
if (status < 0)
goto fail;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 53c87254be4c..5b2cbb778162 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -210,7 +210,7 @@ static int drm_mode_object_get(struct drm_device *dev,
int ret;
WARN(!mutex_is_locked(&dev->mode_config.mutex),
- "%s called w/o mode_config lock\n", __FUNCTION__);
+ "%s called w/o mode_config lock\n", __func__);
again:
if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) {
DRM_ERROR("Ran out memory getting a mode number\n");
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index d8a982b71296..964c5eb1fada 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -36,7 +36,7 @@
/*
* Detailed mode info for 800x600@60Hz
*/
-static struct drm_display_mode std_mode[] = {
+static struct drm_display_mode std_modes[] = {
{ DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 40000, 800, 840,
968, 1056, 0, 600, 601, 605, 628, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
@@ -60,15 +60,18 @@ static struct drm_display_mode std_mode[] = {
* changes have occurred.
*
* FIXME: take into account monitor limits
+ *
+ * RETURNS:
+ * Number of modes found on @connector.
*/
-void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
- uint32_t maxX, uint32_t maxY)
+int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
+ uint32_t maxX, uint32_t maxY)
{
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode, *t;
struct drm_connector_helper_funcs *connector_funcs =
connector->helper_private;
- int ret;
+ int count = 0;
DRM_DEBUG("%s\n", drm_get_connector_name(connector));
/* set all modes to the unverified state */
@@ -81,14 +84,14 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
DRM_DEBUG("%s is disconnected\n",
drm_get_connector_name(connector));
/* TODO set EDID to NULL */
- return;
+ return 0;
}
- ret = (*connector_funcs->get_modes)(connector);
+ count = (*connector_funcs->get_modes)(connector);
+ if (!count)
+ return 0;
- if (ret) {
- drm_mode_connector_list_update(connector);
- }
+ drm_mode_connector_list_update(connector);
if (maxX && maxY)
drm_mode_validate_size(dev, &connector->modes, maxX,
@@ -102,25 +105,8 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
drm_mode_prune_invalid(dev, &connector->modes, true);
- if (list_empty(&connector->modes)) {
- struct drm_display_mode *stdmode;
-
- DRM_DEBUG("No valid modes on %s\n",
- drm_get_connector_name(connector));
-
- /* Should we do this here ???
- * When no valid EDID modes are available we end up
- * here and bailed in the past, now we add a standard
- * 640x480@60Hz mode and carry on.
- */
- stdmode = drm_mode_duplicate(dev, &std_mode[0]);
- drm_mode_probed_add(connector, stdmode);
- drm_mode_list_concat(&connector->probed_modes,
- &connector->modes);
-
- DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n",
- drm_get_connector_name(connector));
- }
+ if (list_empty(&connector->modes))
+ return 0;
drm_mode_sort(&connector->modes);
@@ -131,20 +117,58 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
drm_mode_debug_printmodeline(mode);
}
+
+ return count;
}
EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
-void drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
+int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
uint32_t maxY)
{
struct drm_connector *connector;
+ int count = 0;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- drm_helper_probe_single_connector_modes(connector, maxX, maxY);
+ count += drm_helper_probe_single_connector_modes(connector,
+ maxX, maxY);
}
+
+ return count;
}
EXPORT_SYMBOL(drm_helper_probe_connector_modes);
+static void drm_helper_add_std_modes(struct drm_device *dev,
+ struct drm_connector *connector)
+{
+ struct drm_display_mode *mode, *t;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(std_modes); i++) {
+ struct drm_display_mode *stdmode;
+
+ /*
+ * When no valid EDID modes are available we end up
+ * here and bailed in the past, now we add some standard
+ * modes and move on.
+ */
+ stdmode = drm_mode_duplicate(dev, &std_modes[i]);
+ drm_mode_probed_add(connector, stdmode);
+ drm_mode_list_concat(&connector->probed_modes,
+ &connector->modes);
+
+ DRM_DEBUG("Adding mode %s to %s\n", stdmode->name,
+ drm_get_connector_name(connector));
+ }
+ drm_mode_sort(&connector->modes);
+
+ DRM_DEBUG("Added std modes on %s\n", drm_get_connector_name(connector));
+ list_for_each_entry_safe(mode, t, &connector->modes, head) {
+ mode->vrefresh = drm_mode_vrefresh(mode);
+
+ drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+ drm_mode_debug_printmodeline(mode);
+ }
+}
/**
* drm_helper_crtc_in_use - check if a given CRTC is in a mode_config
@@ -237,6 +261,8 @@ static void drm_enable_connectors(struct drm_device *dev, bool *enabled)
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
enabled[i] = drm_connector_enabled(connector, true);
+ DRM_DEBUG("connector %d enabled? %s\n", connector->base.id,
+ enabled[i] ? "yes" : "no");
any_enabled |= enabled[i];
i++;
}
@@ -265,11 +291,17 @@ static bool drm_target_preferred(struct drm_device *dev,
continue;
}
+ DRM_DEBUG("looking for preferred mode on connector %d\n",
+ connector->base.id);
+
modes[i] = drm_has_preferred_mode(connector, width, height);
- if (!modes[i]) {
+ /* No preferred modes, pick one off the list */
+ if (!modes[i] && !list_empty(&connector->modes)) {
list_for_each_entry(modes[i], &connector->modes, head)
break;
}
+ DRM_DEBUG("found mode %s\n", modes[i] ? modes[i]->name :
+ "none");
i++;
}
return true;
@@ -369,6 +401,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
int width, height;
int i, ret;
+ DRM_DEBUG("\n");
+
width = dev->mode_config.max_width;
height = dev->mode_config.max_height;
@@ -390,6 +424,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
if (!ret)
DRM_ERROR("Unable to find initial modes\n");
+ DRM_DEBUG("picking CRTCs for %dx%d config\n", width, height);
+
drm_pick_crtcs(dev, crtcs, modes, 0, width, height);
i = 0;
@@ -403,6 +439,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
}
if (mode && crtc) {
+ DRM_DEBUG("desired mode %s set on crtc %d\n",
+ mode->name, crtc->base.id);
crtc->desired_mode = mode;
connector->encoder->crtc = crtc;
} else
@@ -442,6 +480,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
int saved_x, saved_y;
struct drm_encoder *encoder;
bool ret = true;
+ bool depth_changed, bpp_changed;
adjusted_mode = drm_mode_duplicate(dev, mode);
@@ -450,6 +489,15 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
if (!crtc->enabled)
return true;
+ if (old_fb && crtc->fb) {
+ depth_changed = (old_fb->depth != crtc->fb->depth);
+ bpp_changed = (old_fb->bits_per_pixel !=
+ crtc->fb->bits_per_pixel);
+ } else {
+ depth_changed = true;
+ bpp_changed = true;
+ }
+
saved_mode = crtc->mode;
saved_x = crtc->x;
saved_y = crtc->y;
@@ -462,7 +510,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
crtc->y = y;
if (drm_mode_equal(&saved_mode, &crtc->mode)) {
- if (saved_x != crtc->x || saved_y != crtc->y) {
+ if (saved_x != crtc->x || saved_y != crtc->y ||
+ depth_changed || bpp_changed) {
crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
old_fb);
goto done;
@@ -568,8 +617,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
struct drm_encoder **save_encoders, *new_encoder;
struct drm_framebuffer *old_fb;
bool save_enabled;
- bool changed = false;
- bool flip_or_move = false;
+ bool mode_changed = false;
+ bool fb_changed = false;
struct drm_connector *connector;
int count = 0, ro, fail = 0;
struct drm_crtc_helper_funcs *crtc_funcs;
@@ -597,7 +646,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
/* save previous config */
save_enabled = set->crtc->enabled;
- /* this is meant to be num_connector not num_crtc */
+ /*
+ * We do mode_config.num_connectors here since we'll look at the
+ * CRTC and encoder associated with each connector later.
+ */
save_crtcs = kzalloc(dev->mode_config.num_connector *
sizeof(struct drm_crtc *), GFP_KERNEL);
if (!save_crtcs)
@@ -613,21 +665,25 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
/* We should be able to check here if the fb has the same properties
* and then just flip_or_move it */
if (set->crtc->fb != set->fb) {
- /* if we have no fb then its a change not a flip */
+ /* If we have no fb then treat it as a full mode set */
if (set->crtc->fb == NULL)
- changed = true;
+ mode_changed = true;
+ else if ((set->fb->bits_per_pixel !=
+ set->crtc->fb->bits_per_pixel) ||
+ set->fb->depth != set->crtc->fb->depth)
+ fb_changed = true;
else
- flip_or_move = true;
+ fb_changed = true;
}
if (set->x != set->crtc->x || set->y != set->crtc->y)
- flip_or_move = true;
+ fb_changed = true;
if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
DRM_DEBUG("modes are different\n");
drm_mode_debug_printmodeline(&set->crtc->mode);
drm_mode_debug_printmodeline(set->mode);
- changed = true;
+ mode_changed = true;
}
/* a) traverse passed in connector list and get encoders for them */
@@ -650,7 +706,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
}
if (new_encoder != connector->encoder) {
- changed = true;
+ mode_changed = true;
connector->encoder = new_encoder;
}
}
@@ -677,16 +733,16 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
new_crtc = set->crtc;
}
if (new_crtc != connector->encoder->crtc) {
- changed = true;
+ mode_changed = true;
connector->encoder->crtc = new_crtc;
}
}
/* mode_set_base is not a required function */
- if (flip_or_move && !crtc_funcs->mode_set_base)
- changed = true;
+ if (fb_changed && !crtc_funcs->mode_set_base)
+ mode_changed = true;
- if (changed) {
+ if (mode_changed) {
old_fb = set->crtc->fb;
set->crtc->fb = set->fb;
set->crtc->enabled = (set->mode != NULL);
@@ -705,7 +761,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
set->crtc->desired_mode = set->mode;
}
drm_helper_disable_unused_functions(dev);
- } else if (flip_or_move) {
+ } else if (fb_changed) {
old_fb = set->crtc->fb;
if (set->crtc->fb != set->fb)
set->crtc->fb = set->fb;
@@ -764,10 +820,31 @@ bool drm_helper_plugged_event(struct drm_device *dev)
*/
bool drm_helper_initial_config(struct drm_device *dev, bool can_grow)
{
- int ret = false;
+ struct drm_connector *connector;
+ int count = 0;
- drm_helper_plugged_event(dev);
- return ret;
+ count = drm_helper_probe_connector_modes(dev,
+ dev->mode_config.max_width,
+ dev->mode_config.max_height);
+
+ /*
+ * None of the available connectors had any modes, so add some
+ * and try to light them up anyway
+ */
+ if (!count) {
+ DRM_ERROR("connectors have no modes, using standard modes\n");
+ list_for_each_entry(connector,
+ &dev->mode_config.connector_list,
+ head)
+ drm_helper_add_std_modes(dev, connector);
+ }
+
+ drm_setup_crtcs(dev);
+
+ /* alert the driver fb layer */
+ dev->mode_config.funcs->fb_changed(dev);
+
+ return 0;
}
EXPORT_SYMBOL(drm_helper_initial_config);
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 724e505873cf..477caa1b1e4b 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -267,7 +267,8 @@ EXPORT_SYMBOL(drm_irq_install);
*/
int drm_irq_uninstall(struct drm_device * dev)
{
- int irq_enabled;
+ unsigned long irqflags;
+ int irq_enabled, i;
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL;
@@ -277,6 +278,16 @@ int drm_irq_uninstall(struct drm_device * dev)
dev->irq_enabled = 0;
mutex_unlock(&dev->struct_mutex);
+ /*
+ * Wake up any waiters so they don't hang.
+ */
+ spin_lock_irqsave(&dev->vbl_lock, irqflags);
+ for (i = 0; i < dev->num_crtcs; i++) {
+ DRM_WAKEUP(&dev->vbl_queue[i]);
+ dev->vblank_enabled[i] = 0;
+ }
+ spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+
if (!irq_enabled)
return -EINVAL;
@@ -652,8 +663,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
vblwait->request.sequence, crtc);
dev->last_vblank_wait[crtc] = vblwait->request.sequence;
DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
- ((drm_vblank_count(dev, crtc)
- - vblwait->request.sequence) <= (1 << 23)));
+ (((drm_vblank_count(dev, crtc) -
+ vblwait->request.sequence) <= (1 << 23)) ||
+ !dev->irq_enabled));
if (ret != -EINTR) {
struct timeval now;
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 62a4bf7b49df..bbadf1c04142 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -177,6 +177,14 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+ master_priv->sarea = drm_getsarea(dev);
+ if (master_priv->sarea) {
+ master_priv->sarea_priv = (drm_i915_sarea_t *)
+ ((u8 *)master_priv->sarea->handle + init->sarea_priv_offset);
+ } else {
+ DRM_DEBUG("sarea not found assuming DRI2 userspace\n");
+ }
+
if (init->ring_size != 0) {
if (dev_priv->ring.ring_obj != NULL) {
i915_dma_cleanup(dev);
@@ -1152,6 +1160,8 @@ int i915_driver_unload(struct drm_device *dev)
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
intel_modeset_cleanup(dev);
+ i915_gem_free_all_phys_object(dev);
+
mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 563de18063fd..e13518252007 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -72,6 +72,18 @@ enum pipe {
#define WATCH_INACTIVE 0
#define WATCH_PWRITE 0
+#define I915_GEM_PHYS_CURSOR_0 1
+#define I915_GEM_PHYS_CURSOR_1 2
+#define I915_GEM_PHYS_OVERLAY_REGS 3
+#define I915_MAX_PHYS_OBJECT (I915_GEM_PHYS_OVERLAY_REGS)
+
+struct drm_i915_gem_phys_object {
+ int id;
+ struct page **page_list;
+ drm_dma_handle_t *handle;
+ struct drm_gem_object *cur_obj;
+};
+
typedef struct _drm_i915_ring_buffer {
int tail_mask;
unsigned long Size;
@@ -358,6 +370,9 @@ typedef struct drm_i915_private {
uint32_t bit_6_swizzle_x;
/** Bit 6 swizzling required for Y tiling */
uint32_t bit_6_swizzle_y;
+
+ /* storage for physical objects */
+ struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
} mm;
} drm_i915_private_t;
@@ -436,6 +451,9 @@ struct drm_i915_gem_object {
/** User space pin count and filp owning the pin */
uint32_t user_pin_count;
struct drm_file *pin_filp;
+
+ /** for phy allocated objects */
+ struct drm_i915_gem_phys_object *phys_obj;
};
/**
@@ -598,6 +616,11 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start,
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
int write);
+int i915_gem_attach_phys_object(struct drm_device *dev,
+ struct drm_gem_object *obj, int id);
+void i915_gem_detach_phys_object(struct drm_device *dev,
+ struct drm_gem_object *obj);
+void i915_gem_free_all_phys_object(struct drm_device *dev);
/* i915_gem_tiling.c */
void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 14afc23a0e24..96316fd47233 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -55,6 +55,9 @@ static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
static int i915_gem_evict_something(struct drm_device *dev);
+static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
+ struct drm_i915_gem_pwrite *args,
+ struct drm_file *file_priv);
int i915_gem_do_init(struct drm_device *dev, unsigned long start,
unsigned long end)
@@ -386,8 +389,10 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
* pread/pwrite currently are reading and writing from the CPU
* perspective, requiring manual detiling by the client.
*/
- if (obj_priv->tiling_mode == I915_TILING_NONE &&
- dev->gtt_total != 0)
+ if (obj_priv->phys_obj)
+ ret = i915_gem_phys_pwrite(dev, obj, args, file_priv);
+ else if (obj_priv->tiling_mode == I915_TILING_NONE &&
+ dev->gtt_total != 0)
ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv);
else
ret = i915_gem_shmem_pwrite(dev, obj, args, file_priv);
@@ -1445,7 +1450,7 @@ static void i915_write_fence_reg(struct drm_i915_fence_reg *reg)
if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) ||
(obj_priv->gtt_offset & (obj->size - 1))) {
- WARN(1, "%s: object not 1M or size aligned\n", __FUNCTION__);
+ WARN(1, "%s: object not 1M or size aligned\n", __func__);
return;
}
@@ -1478,7 +1483,7 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) ||
(obj_priv->gtt_offset & (obj->size - 1))) {
- WARN(1, "%s: object not 1M or size aligned\n", __FUNCTION__);
+ WARN(1, "%s: object not 1M or size aligned\n", __func__);
return;
}
@@ -2858,6 +2863,9 @@ void i915_gem_free_object(struct drm_gem_object *obj)
while (obj_priv->pin_count > 0)
i915_gem_object_unpin(obj);
+ if (obj_priv->phys_obj)
+ i915_gem_detach_phys_object(dev, obj);
+
i915_gem_object_unbind(obj);
list = &obj->map_list;
@@ -3293,3 +3301,180 @@ i915_gem_load(struct drm_device *dev)
i915_gem_detect_bit_6_swizzle(dev);
}
+
+/*
+ * Create a physically contiguous memory object for this object
+ * e.g. for cursor + overlay regs
+ */
+int i915_gem_init_phys_object(struct drm_device *dev,
+ int id, int size)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_phys_object *phys_obj;
+ int ret;
+
+ if (dev_priv->mm.phys_objs[id - 1] || !size)
+ return 0;
+
+ phys_obj = drm_calloc(1, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER);
+ if (!phys_obj)
+ return -ENOMEM;
+
+ phys_obj->id = id;
+
+ phys_obj->handle = drm_pci_alloc(dev, size, 0, 0xffffffff);
+ if (!phys_obj->handle) {
+ ret = -ENOMEM;
+ goto kfree_obj;
+ }
+#ifdef CONFIG_X86
+ set_memory_wc((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
+#endif
+
+ dev_priv->mm.phys_objs[id - 1] = phys_obj;
+
+ return 0;
+kfree_obj:
+ drm_free(phys_obj, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER);
+ return ret;
+}
+
+void i915_gem_free_phys_object(struct drm_device *dev, int id)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_phys_object *phys_obj;
+
+ if (!dev_priv->mm.phys_objs[id - 1])
+ return;
+
+ phys_obj = dev_priv->mm.phys_objs[id - 1];
+ if (phys_obj->cur_obj) {
+ i915_gem_detach_phys_object(dev, phys_obj->cur_obj);
+ }
+
+#ifdef CONFIG_X86
+ set_memory_wb((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
+#endif
+ drm_pci_free(dev, phys_obj->handle);
+ kfree(phys_obj);
+ dev_priv->mm.phys_objs[id - 1] = NULL;
+}
+
+void i915_gem_free_all_phys_object(struct drm_device *dev)
+{
+ int i;
+
+ for (i = 0; i < I915_MAX_PHYS_OBJECT; i++)
+ i915_gem_free_phys_object(dev, i);
+}
+
+void i915_gem_detach_phys_object(struct drm_device *dev,
+ struct drm_gem_object *obj)
+{
+ struct drm_i915_gem_object *obj_priv;
+ int i;
+ int ret;
+ int page_count;
+
+ obj_priv = obj->driver_private;
+ if (!obj_priv->phys_obj)
+ return;
+
+ ret = i915_gem_object_get_page_list(obj);
+ if (ret)
+ goto out;
+
+ page_count = obj->size / PAGE_SIZE;
+
+ for (i = 0; i < page_count; i++) {
+ char *dst = kmap_atomic(obj_priv->page_list[i], KM_USER0);
+ char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
+
+ memcpy(dst, src, PAGE_SIZE);
+ kunmap_atomic(dst, KM_USER0);
+ }
+ drm_clflush_pages(obj_priv->page_list, page_count);
+ drm_agp_chipset_flush(dev);
+out:
+ obj_priv->phys_obj->cur_obj = NULL;
+ obj_priv->phys_obj = NULL;
+}
+
+int
+i915_gem_attach_phys_object(struct drm_device *dev,
+ struct drm_gem_object *obj, int id)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv;
+ int ret = 0;
+ int page_count;
+ int i;
+
+ if (id > I915_MAX_PHYS_OBJECT)
+ return -EINVAL;
+
+ obj_priv = obj->driver_private;
+
+ if (obj_priv->phys_obj) {
+ if (obj_priv->phys_obj->id == id)
+ return 0;
+ i915_gem_detach_phys_object(dev, obj);
+ }
+
+
+ /* create a new object */
+ if (!dev_priv->mm.phys_objs[id - 1]) {
+ ret = i915_gem_init_phys_object(dev, id,
+ obj->size);
+ if (ret) {
+ DRM_ERROR("failed to init phys object %d size: %d\n", id, obj->size);
+ goto out;
+ }
+ }
+
+ /* bind to the object */
+ obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1];
+ obj_priv->phys_obj->cur_obj = obj;
+
+ ret = i915_gem_object_get_page_list(obj);
+ if (ret) {
+ DRM_ERROR("failed to get page list\n");
+ goto out;
+ }
+
+ page_count = obj->size / PAGE_SIZE;
+
+ for (i = 0; i < page_count; i++) {
+ char *src = kmap_atomic(obj_priv->page_list[i], KM_USER0);
+ char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
+
+ memcpy(dst, src, PAGE_SIZE);
+ kunmap_atomic(src, KM_USER0);
+ }
+
+ return 0;
+out:
+ return ret;
+}
+
+static int
+i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
+ struct drm_i915_gem_pwrite *args,
+ struct drm_file *file_priv)
+{
+ struct drm_i915_gem_object *obj_priv = obj->driver_private;
+ void *obj_addr;
+ int ret;
+ char __user *user_data;
+
+ user_data = (char __user *) (uintptr_t) args->data_ptr;
+ obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;
+
+ DRM_ERROR("obj_addr %p, %lld\n", obj_addr, args->size);
+ ret = copy_from_user(obj_addr, user_data, args->size);
+ if (ret)
+ return -EFAULT;
+
+ drm_agp_chipset_flush(dev);
+ return 0;
+}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 0cadafbef411..6290219de6c8 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -411,6 +411,12 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags;
+ int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+ u32 pipeconf;
+
+ pipeconf = I915_READ(pipeconf_reg);
+ if (!(pipeconf & PIPEACONF_ENABLE))
+ return -EINVAL;
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
if (IS_I965G(dev))
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 8ccb9c3ab868..31c3732b7a69 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -401,6 +401,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
I915_WRITE(dspstride, crtc->fb->pitch);
dspcntr = I915_READ(dspcntr_reg);
+ /* Mask out pixel format bits in case we change it */
+ dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
switch (crtc->fb->bits_per_pixel) {
case 8:
dspcntr |= DISPPLANE_8BPP;
@@ -1014,21 +1016,25 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
if (bo->size < width * height * 4) {
DRM_ERROR("buffer is to small\n");
- drm_gem_object_unreference(bo);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto fail;
}
- if (dev_priv->cursor_needs_physical) {
- addr = dev->agp->base + obj_priv->gtt_offset;
- } else {
+ /* we only need to pin inside GTT if cursor is non-phy */
+ if (!dev_priv->cursor_needs_physical) {
+ ret = i915_gem_object_pin(bo, PAGE_SIZE);
+ if (ret) {
+ DRM_ERROR("failed to pin cursor bo\n");
+ goto fail;
+ }
addr = obj_priv->gtt_offset;
- }
-
- ret = i915_gem_object_pin(bo, PAGE_SIZE);
- if (ret) {
- DRM_ERROR("failed to pin cursor bo\n");
- drm_gem_object_unreference(bo);
- return ret;
+ } else {
+ ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
+ if (ret) {
+ DRM_ERROR("failed to attach phys object\n");
+ goto fail;
+ }
+ addr = obj_priv->phys_obj->handle->busaddr;
}
temp = 0;
@@ -1041,14 +1047,25 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
I915_WRITE(base, addr);
if (intel_crtc->cursor_bo) {
- i915_gem_object_unpin(intel_crtc->cursor_bo);
+ if (dev_priv->cursor_needs_physical) {
+ if (intel_crtc->cursor_bo != bo)
+ i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
+ } else
+ i915_gem_object_unpin(intel_crtc->cursor_bo);
+ mutex_lock(&dev->struct_mutex);
drm_gem_object_unreference(intel_crtc->cursor_bo);
+ mutex_unlock(&dev->struct_mutex);
}
intel_crtc->cursor_addr = addr;
intel_crtc->cursor_bo = bo;
return 0;
+fail:
+ mutex_lock(&dev->struct_mutex);
+ drm_gem_object_unreference(bo);
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
}
static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index ccecfaf6307b..2fafdcc108fe 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -456,6 +456,13 @@ void intel_lvds_init(struct drm_device *dev)
dev_priv->panel_fixed_mode =
drm_mode_duplicate(dev, dev_priv->vbt_mode);
mutex_unlock(&dev->mode_config.mutex);
+ if (dev_priv->panel_fixed_mode) {
+ dev_priv->panel_fixed_mode->type |=
+ DRM_MODE_TYPE_PREFERRED;
+ drm_mode_probed_add(connector,
+ dev_priv->panel_fixed_mode);
+ goto out;
+ }
}
/*
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 03cb494af1c5..f0a0f72238ab 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -102,7 +102,7 @@ static void hid_reset(struct work_struct *work)
struct usbhid_device *usbhid =
container_of(work, struct usbhid_device, reset_work);
struct hid_device *hid = usbhid->hid;
- int rc_lock, rc = 0;
+ int rc = 0;
if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) {
dev_dbg(&usbhid->intf->dev, "clear halt\n");
@@ -113,11 +113,10 @@ static void hid_reset(struct work_struct *work)
else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) {
dev_dbg(&usbhid->intf->dev, "resetting device\n");
- rc = rc_lock = usb_lock_device_for_reset(hid_to_usb_dev(hid), usbhid->intf);
- if (rc_lock >= 0) {
+ rc = usb_lock_device_for_reset(hid_to_usb_dev(hid), usbhid->intf);
+ if (rc == 0) {
rc = usb_reset_device(hid_to_usb_dev(hid));
- if (rc_lock)
- usb_unlock_device(hid_to_usb_dev(hid));
+ usb_unlock_device(hid_to_usb_dev(hid));
}
clear_bit(HID_RESET_PENDING, &usbhid->iofl);
}
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 6a98f9f572b0..d73eea382ab3 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -874,12 +874,14 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
INIT_LIST_HEAD(&hiddev->list);
spin_lock_init(&hiddev->list_lock);
mutex_init(&hiddev->existancelock);
+ hid->hiddev = hiddev;
hiddev->hid = hid;
hiddev->exist = 1;
retval = usb_register_dev(usbhid->intf, &hiddev_class);
if (retval) {
err_hid("Not able to get a minor for this device.");
+ hid->hiddev = NULL;
kfree(hiddev);
return -1;
} else {
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index c709e821f04b..b84bf066879b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -189,6 +189,16 @@ config SENSORS_ADT7473
This driver can also be built as a module. If so, the module
will be called adt7473.
+config SENSORS_ADT7475
+ tristate "Analog Devices ADT7475"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Analog Devices
+ ADT7475 hardware monitoring chips.
+
+ This driver can also be build as a module. If so, the module
+ will be called adt7475.
+
config SENSORS_K8TEMP
tristate "AMD Athlon64/FX or Opteron temperature sensor"
depends on X86 && PCI && EXPERIMENTAL
@@ -284,11 +294,12 @@ config SENSORS_F71805F
will be called f71805f.
config SENSORS_F71882FG
- tristate "Fintek F71882FG and F71883FG"
+ tristate "Fintek F71862FG, F71882FG and F8000"
depends on EXPERIMENTAL
help
If you say yes here you get support for hardware monitoring
- features of the Fintek F71882FG and F71883FG Super-I/O chips.
+ features of the Fintek F71882FG/F71883FG, F71862FG/71863FG
+ and F8000 Super-I/O chips.
This driver can also be built as a module. If so, the module
will be called f71882fg.
@@ -304,9 +315,13 @@ config SENSORS_F75375S
will be called f75375s.
config SENSORS_FSCHER
- tristate "FSC Hermes"
+ tristate "FSC Hermes (DEPRECATED)"
depends on X86 && I2C
help
+ This driver is DEPRECATED please use the new merged fschmd
+ ("FSC Poseidon, Scylla, Hermes, Heimdall and Heracles") driver
+ instead.
+
If you say yes here you get support for Fujitsu Siemens
Computers Hermes sensor chips.
@@ -314,9 +329,13 @@ config SENSORS_FSCHER
will be called fscher.
config SENSORS_FSCPOS
- tristate "FSC Poseidon"
+ tristate "FSC Poseidon (DEPRECATED)"
depends on X86 && I2C
help
+ This driver is DEPRECATED please use the new merged fschmd
+ ("FSC Poseidon, Scylla, Hermes, Heimdall and Heracles") driver
+ instead.
+
If you say yes here you get support for Fujitsu Siemens
Computers Poseidon sensor chips.
@@ -325,14 +344,15 @@ config SENSORS_FSCPOS
config SENSORS_FSCHMD
tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles"
- depends on X86 && I2C && EXPERIMENTAL
+ depends on X86 && I2C
help
If you say yes here you get support for various Fujitsu Siemens
- Computers sensor chips.
+ Computers sensor chips, including support for the integrated
+ watchdog.
- This is a new merged driver for FSC sensor chips which is intended
- as a replacment for the fscpos, fscscy and fscher drivers and adds
- support for several other FCS sensor chips.
+ This is a merged driver for FSC sensor chips replacing the fscpos,
+ fscscy and fscher drivers and adding support for several other FSC
+ sensor chips.
This driver can also be built as a module. If so, the module
will be called fschmd.
@@ -399,7 +419,8 @@ config SENSORS_IT87
select HWMON_VID
help
If you say yes here you get support for ITE IT8705F, IT8712F,
- IT8716F, IT8718F and IT8726F sensor chips, and the SiS960 clone.
+ IT8716F, IT8718F, IT8720F and IT8726F sensor chips, and the
+ SiS960 clone.
This driver can also be built as a module. If so, the module
will be called it87.
@@ -417,11 +438,12 @@ config SENSORS_LM63
will be called lm63.
config SENSORS_LM70
- tristate "National Semiconductor LM70"
+ tristate "National Semiconductor LM70 / Texas Instruments TMP121"
depends on SPI_MASTER && EXPERIMENTAL
help
If you say yes here you get support for the National Semiconductor
- LM70 digital temperature sensor chip.
+ LM70 and Texas Instruments TMP121/TMP123 digital temperature
+ sensor chips.
This driver can also be built as a module. If so, the module
will be called lm70.
@@ -548,6 +570,17 @@ config SENSORS_LM93
This driver can also be built as a module. If so, the module
will be called lm93.
+config SENSORS_LTC4245
+ tristate "Linear Technology LTC4245"
+ depends on I2C && EXPERIMENTAL
+ default n
+ help
+ If you say yes here you get support for Linear Technology LTC4245
+ Multiple Supply Hot Swap Controller I2C interface.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc4245.
+
config SENSORS_MAX1111
tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip"
depends on SPI_MASTER
@@ -838,6 +871,8 @@ config SENSORS_HDAPS
config SENSORS_LIS3LV02D
tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer"
depends on ACPI && INPUT
+ select NEW_LEDS
+ select LEDS_CLASS
default n
help
This driver provides support for the LIS3LV02Dx accelerometer. In
@@ -849,10 +884,16 @@ config SENSORS_LIS3LV02D
/sys/devices/platform/lis3lv02d.
This driver also provides an absolute input class device, allowing
- the laptop to act as a pinball machine-esque joystick.
+ the laptop to act as a pinball machine-esque joystick. On HP laptops,
+ if the led infrastructure is activated, support for a led indicating
+ disk protection will be provided as hp:red:hddprotection.
- This driver can also be built as a module. If so, the module
- will be called lis3lv02d.
+ This driver can also be built as modules. If so, the core module
+ will be called lis3lv02d and a specific module for HP laptops will be
+ called hp_accel.
+
+ Say Y here if you have an applicable laptop and want to experience
+ the awesome power of lis3lv02d.
config SENSORS_APPLESMC
tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 58fc5be5355d..2e80f37f39eb 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -28,6 +28,8 @@ obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o
obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
obj-$(CONFIG_SENSORS_ADT7473) += adt7473.o
+obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
+
obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_AMS) += ams/
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
@@ -49,7 +51,7 @@ obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
-obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o
+obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o
obj-$(CONFIG_SENSORS_LM63) += lm63.o
obj-$(CONFIG_SENSORS_LM70) += lm70.o
obj-$(CONFIG_SENSORS_LM75) += lm75.o
@@ -62,6 +64,7 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o
obj-$(CONFIG_SENSORS_LM90) += lm90.o
obj-$(CONFIG_SENSORS_LM92) += lm92.o
obj-$(CONFIG_SENSORS_LM93) += lm93.o
+obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o
obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index 70bb854086df..e52b38806d03 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -279,7 +279,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
{ "OTES1 Fan", 36, 2, 60, 1, 0 },
{ NULL, 0, 0, 0, 0, 0 } }
},
- { 0x0011, "AT8 32X(ATI RD580-ULI M1575)", {
+ { 0x0011, "AT8 32X", {
{ "CPU Core", 0, 0, 10, 1, 0 },
{ "DDR", 1, 0, 20, 1, 0 },
{ "DDR VTT", 2, 0, 10, 1, 0 },
@@ -402,7 +402,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
{ "AUX3 Fan", 36, 2, 60, 1, 0 },
{ NULL, 0, 0, 0, 0, 0 } }
},
- { 0x0016, "AW9D-MAX (Intel i975-ICH7)", {
+ { 0x0016, "AW9D-MAX", {
{ "CPU Core", 0, 0, 10, 1, 0 },
{ "DDR2", 1, 0, 20, 1, 0 },
{ "DDR2 VTT", 2, 0, 10, 1, 0 },
@@ -482,7 +482,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
{ "AUX3 Fan", 36, 2, 60, 1, 0 },
{ NULL, 0, 0, 0, 0, 0 } }
},
- { 0x0019, NULL /* Unknown, need DMI string */, {
+ { 0x0019, "IN9 32X MAX", {
{ "CPU Core", 7, 0, 10, 1, 0 },
{ "DDR2", 13, 0, 20, 1, 0 },
{ "DDR2 VTT", 14, 0, 10, 1, 0 },
@@ -509,7 +509,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
{ "AUX3 FAN", 36, 2, 60, 1, 0 },
{ NULL, 0, 0, 0, 0, 0 } }
},
- { 0x001A, "IP35 Pro(Intel P35-ICH9R)", {
+ { 0x001A, "IP35 Pro", {
{ "CPU Core", 0, 0, 10, 1, 0 },
{ "DDR2", 1, 0, 20, 1, 0 },
{ "DDR2 VTT", 2, 0, 10, 1, 0 },
@@ -1128,6 +1128,7 @@ static int __init abituguru3_dmi_detect(void)
{
const char *board_vendor, *board_name;
int i, err = (force) ? 1 : -ENODEV;
+ size_t sublen;
board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
if (!board_vendor || strcmp(board_vendor, "http://www.abit.com.tw/"))
@@ -1137,9 +1138,20 @@ static int __init abituguru3_dmi_detect(void)
if (!board_name)
return err;
+ /* At the moment, we don't care about the part of the vendor
+ * DMI string contained in brackets. Truncate the string at
+ * the first occurrence of a bracket. Trim any trailing space
+ * from the substring.
+ */
+ sublen = strcspn(board_name, "(");
+ while (sublen > 0 && board_name[sublen - 1] == ' ')
+ sublen--;
+
for (i = 0; abituguru3_motherboards[i].id; i++) {
const char *dmi_name = abituguru3_motherboards[i].dmi_name;
- if (dmi_name && !strcmp(dmi_name, board_name))
+ if (!dmi_name || strlen(dmi_name) != sublen)
+ continue;
+ if (!strncasecmp(board_name, dmi_name, sublen))
break;
}
@@ -1153,7 +1165,7 @@ static int __init abituguru3_dmi_detect(void)
static inline int abituguru3_dmi_detect(void)
{
- return -ENODEV;
+ return 1;
}
#endif /* CONFIG_DMI */
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c
new file mode 100644
index 000000000000..d39877a7da63
--- /dev/null
+++ b/drivers/hwmon/adt7475.c
@@ -0,0 +1,1221 @@
+/*
+ * adt7475 - Thermal sensor driver for the ADT7475 chip and derivatives
+ * Copyright (C) 2007-2008, Advanced Micro Devices, Inc.
+ * Copyright (C) 2008 Jordan Crouse <jordan@cosmicpenguin.net>
+ * Copyright (C) 2008 Hans de Goede <hdegoede@redhat.com>
+
+ * Derived from the lm83 driver by Jean Delvare
+ *
+ * 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/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+
+/* Indexes for the sysfs hooks */
+
+#define INPUT 0
+#define MIN 1
+#define MAX 2
+#define CONTROL 3
+#define OFFSET 3
+#define AUTOMIN 4
+#define THERM 5
+#define HYSTERSIS 6
+
+/* These are unique identifiers for the sysfs functions - unlike the
+ numbers above, these are not also indexes into an array
+*/
+
+#define ALARM 9
+#define FAULT 10
+
+/* 7475 Common Registers */
+
+#define REG_VOLTAGE_BASE 0x21
+#define REG_TEMP_BASE 0x25
+#define REG_TACH_BASE 0x28
+#define REG_PWM_BASE 0x30
+#define REG_PWM_MAX_BASE 0x38
+
+#define REG_DEVID 0x3D
+#define REG_VENDID 0x3E
+
+#define REG_STATUS1 0x41
+#define REG_STATUS2 0x42
+
+#define REG_VOLTAGE_MIN_BASE 0x46
+#define REG_VOLTAGE_MAX_BASE 0x47
+
+#define REG_TEMP_MIN_BASE 0x4E
+#define REG_TEMP_MAX_BASE 0x4F
+
+#define REG_TACH_MIN_BASE 0x54
+
+#define REG_PWM_CONFIG_BASE 0x5C
+
+#define REG_TEMP_TRANGE_BASE 0x5F
+
+#define REG_PWM_MIN_BASE 0x64
+
+#define REG_TEMP_TMIN_BASE 0x67
+#define REG_TEMP_THERM_BASE 0x6A
+
+#define REG_REMOTE1_HYSTERSIS 0x6D
+#define REG_REMOTE2_HYSTERSIS 0x6E
+
+#define REG_TEMP_OFFSET_BASE 0x70
+
+#define REG_EXTEND1 0x76
+#define REG_EXTEND2 0x77
+#define REG_CONFIG5 0x7C
+
+#define CONFIG5_TWOSCOMP 0x01
+#define CONFIG5_TEMPOFFSET 0x02
+
+/* ADT7475 Settings */
+
+#define ADT7475_VOLTAGE_COUNT 2
+#define ADT7475_TEMP_COUNT 3
+#define ADT7475_TACH_COUNT 4
+#define ADT7475_PWM_COUNT 3
+
+/* Macro to read the registers */
+
+#define adt7475_read(reg) i2c_smbus_read_byte_data(client, (reg))
+
+/* Macros to easily index the registers */
+
+#define TACH_REG(idx) (REG_TACH_BASE + ((idx) * 2))
+#define TACH_MIN_REG(idx) (REG_TACH_MIN_BASE + ((idx) * 2))
+
+#define PWM_REG(idx) (REG_PWM_BASE + (idx))
+#define PWM_MAX_REG(idx) (REG_PWM_MAX_BASE + (idx))
+#define PWM_MIN_REG(idx) (REG_PWM_MIN_BASE + (idx))
+#define PWM_CONFIG_REG(idx) (REG_PWM_CONFIG_BASE + (idx))
+
+#define VOLTAGE_REG(idx) (REG_VOLTAGE_BASE + (idx))
+#define VOLTAGE_MIN_REG(idx) (REG_VOLTAGE_MIN_BASE + ((idx) * 2))
+#define VOLTAGE_MAX_REG(idx) (REG_VOLTAGE_MAX_BASE + ((idx) * 2))
+
+#define TEMP_REG(idx) (REG_TEMP_BASE + (idx))
+#define TEMP_MIN_REG(idx) (REG_TEMP_MIN_BASE + ((idx) * 2))
+#define TEMP_MAX_REG(idx) (REG_TEMP_MAX_BASE + ((idx) * 2))
+#define TEMP_TMIN_REG(idx) (REG_TEMP_TMIN_BASE + (idx))
+#define TEMP_THERM_REG(idx) (REG_TEMP_THERM_BASE + (idx))
+#define TEMP_OFFSET_REG(idx) (REG_TEMP_OFFSET_BASE + (idx))
+#define TEMP_TRANGE_REG(idx) (REG_TEMP_TRANGE_BASE + (idx))
+
+static unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD_1(adt7475);
+
+static const struct i2c_device_id adt7475_id[] = {
+ { "adt7475", adt7475 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adt7475_id);
+
+struct adt7475_data {
+ struct device *hwmon_dev;
+ struct mutex lock;
+
+ unsigned long measure_updated;
+ unsigned long limits_updated;
+ char valid;
+
+ u8 config5;
+ u16 alarms;
+ u16 voltage[3][3];
+ u16 temp[7][3];
+ u16 tach[2][4];
+ u8 pwm[4][3];
+ u8 range[3];
+ u8 pwmctl[3];
+ u8 pwmchan[3];
+};
+
+static struct i2c_driver adt7475_driver;
+static struct adt7475_data *adt7475_update_device(struct device *dev);
+static void adt7475_read_hystersis(struct i2c_client *client);
+static void adt7475_read_pwm(struct i2c_client *client, int index);
+
+/* Given a temp value, convert it to register value */
+
+static inline u16 temp2reg(struct adt7475_data *data, long val)
+{
+ u16 ret;
+
+ if (!(data->config5 & CONFIG5_TWOSCOMP)) {
+ val = SENSORS_LIMIT(val, -64000, 191000);
+ ret = (val + 64500) / 1000;
+ } else {
+ val = SENSORS_LIMIT(val, -128000, 127000);
+ if (val < -500)
+ ret = (256500 + val) / 1000;
+ else
+ ret = (val + 500) / 1000;
+ }
+
+ return ret << 2;
+}
+
+/* Given a register value, convert it to a real temp value */
+
+static inline int reg2temp(struct adt7475_data *data, u16 reg)
+{
+ if (data->config5 & CONFIG5_TWOSCOMP) {
+ if (reg >= 512)
+ return (reg - 1024) * 250;
+ else
+ return reg * 250;
+ } else
+ return (reg - 256) * 250;
+}
+
+static inline int tach2rpm(u16 tach)
+{
+ if (tach == 0 || tach == 0xFFFF)
+ return 0;
+
+ return (90000 * 60) / tach;
+}
+
+static inline u16 rpm2tach(unsigned long rpm)
+{
+ if (rpm == 0)
+ return 0;
+
+ return SENSORS_LIMIT((90000 * 60) / rpm, 1, 0xFFFF);
+}
+
+static inline int reg2vcc(u16 reg)
+{
+ return (4296 * reg) / 1000;
+}
+
+static inline int reg2vccp(u16 reg)
+{
+ return (2929 * reg) / 1000;
+}
+
+static inline u16 vcc2reg(long vcc)
+{
+ vcc = SENSORS_LIMIT(vcc, 0, 4396);
+ return (vcc * 1000) / 4296;
+}
+
+static inline u16 vccp2reg(long vcc)
+{
+ vcc = SENSORS_LIMIT(vcc, 0, 2998);
+ return (vcc * 1000) / 2929;
+}
+
+static u16 adt7475_read_word(struct i2c_client *client, int reg)
+{
+ u16 val;
+
+ val = i2c_smbus_read_byte_data(client, reg);
+ val |= (i2c_smbus_read_byte_data(client, reg + 1) << 8);
+
+ return val;
+}
+
+static void adt7475_write_word(struct i2c_client *client, int reg, u16 val)
+{
+ i2c_smbus_write_byte_data(client, reg + 1, val >> 8);
+ i2c_smbus_write_byte_data(client, reg, val & 0xFF);
+}
+
+/* Find the nearest value in a table - used for pwm frequency and
+ auto temp range */
+static int find_nearest(long val, const int *array, int size)
+{
+ int i;
+
+ if (val < array[0])
+ return 0;
+
+ if (val > array[size - 1])
+ return size - 1;
+
+ for (i = 0; i < size - 1; i++) {
+ int a, b;
+
+ if (val > array[i + 1])
+ continue;
+
+ a = val - array[i];
+ b = array[i + 1] - val;
+
+ return (a <= b) ? i : i + 1;
+ }
+
+ return 0;
+}
+
+static ssize_t show_voltage(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct adt7475_data *data = adt7475_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ unsigned short val;
+
+ switch (sattr->nr) {
+ case ALARM:
+ return sprintf(buf, "%d\n",
+ (data->alarms >> (sattr->index + 1)) & 1);
+ default:
+ val = data->voltage[sattr->nr][sattr->index];
+ return sprintf(buf, "%d\n",
+ sattr->index ==
+ 0 ? reg2vccp(val) : reg2vcc(val));
+ }
+}
+
+static ssize_t set_voltage(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ unsigned char reg;
+ long val;
+
+ if (strict_strtol(buf, 10, &val))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+
+ data->voltage[sattr->nr][sattr->index] =
+ sattr->index ? vcc2reg(val) : vccp2reg(val);
+
+ if (sattr->nr == MIN)
+ reg = VOLTAGE_MIN_REG(sattr->index);
+ else
+ reg = VOLTAGE_MAX_REG(sattr->index);
+
+ i2c_smbus_write_byte_data(client, reg,
+ data->voltage[sattr->nr][sattr->index] >> 2);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct adt7475_data *data = adt7475_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int out;
+
+ switch (sattr->nr) {
+ case HYSTERSIS:
+ mutex_lock(&data->lock);
+ out = data->temp[sattr->nr][sattr->index];
+ if (sattr->index != 1)
+ out = (out >> 4) & 0xF;
+ else
+ out = (out & 0xF);
+ /* Show the value as an absolute number tied to
+ * THERM */
+ out = reg2temp(data, data->temp[THERM][sattr->index]) -
+ out * 1000;
+ mutex_unlock(&data->lock);
+ break;
+
+ case OFFSET:
+ /* Offset is always 2's complement, regardless of the
+ * setting in CONFIG5 */
+ mutex_lock(&data->lock);
+ out = (s8)data->temp[sattr->nr][sattr->index];
+ if (data->config5 & CONFIG5_TEMPOFFSET)
+ out *= 1000;
+ else
+ out *= 500;
+ mutex_unlock(&data->lock);
+ break;
+
+ case ALARM:
+ out = (data->alarms >> (sattr->index + 4)) & 1;
+ break;
+
+ case FAULT:
+ /* Note - only for remote1 and remote2 */
+ out = data->alarms & (sattr->index ? 0x8000 : 0x4000);
+ out = out ? 0 : 1;
+ break;
+
+ default:
+ /* All other temp values are in the configured format */
+ out = reg2temp(data, data->temp[sattr->nr][sattr->index]);
+ }
+
+ return sprintf(buf, "%d\n", out);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ unsigned char reg = 0;
+ u8 out;
+ int temp;
+ long val;
+
+ if (strict_strtol(buf, 10, &val))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+
+ /* We need the config register in all cases for temp <-> reg conv. */
+ data->config5 = adt7475_read(REG_CONFIG5);
+
+ switch (sattr->nr) {
+ case OFFSET:
+ if (data->config5 & CONFIG5_TEMPOFFSET) {
+ val = SENSORS_LIMIT(val, -63000, 127000);
+ out = data->temp[OFFSET][sattr->index] = val / 1000;
+ } else {
+ val = SENSORS_LIMIT(val, -63000, 64000);
+ out = data->temp[OFFSET][sattr->index] = val / 500;
+ }
+ break;
+
+ case HYSTERSIS:
+ /* The value will be given as an absolute value, turn it
+ into an offset based on THERM */
+
+ /* Read fresh THERM and HYSTERSIS values from the chip */
+ data->temp[THERM][sattr->index] =
+ adt7475_read(TEMP_THERM_REG(sattr->index)) << 2;
+ adt7475_read_hystersis(client);
+
+ temp = reg2temp(data, data->temp[THERM][sattr->index]);
+ val = SENSORS_LIMIT(val, temp - 15000, temp);
+ val = (temp - val) / 1000;
+
+ if (sattr->index != 1) {
+ data->temp[HYSTERSIS][sattr->index] &= 0xF0;
+ data->temp[HYSTERSIS][sattr->index] |= (val & 0xF) << 4;
+ } else {
+ data->temp[HYSTERSIS][sattr->index] &= 0x0F;
+ data->temp[HYSTERSIS][sattr->index] |= (val & 0xF);
+ }
+
+ out = data->temp[HYSTERSIS][sattr->index];
+ break;
+
+ default:
+ data->temp[sattr->nr][sattr->index] = temp2reg(data, val);
+
+ /* We maintain an extra 2 digits of precision for simplicity
+ * - shift those back off before writing the value */
+ out = (u8) (data->temp[sattr->nr][sattr->index] >> 2);
+ }
+
+ switch (sattr->nr) {
+ case MIN:
+ reg = TEMP_MIN_REG(sattr->index);
+ break;
+ case MAX:
+ reg = TEMP_MAX_REG(sattr->index);
+ break;
+ case OFFSET:
+ reg = TEMP_OFFSET_REG(sattr->index);
+ break;
+ case AUTOMIN:
+ reg = TEMP_TMIN_REG(sattr->index);
+ break;
+ case THERM:
+ reg = TEMP_THERM_REG(sattr->index);
+ break;
+ case HYSTERSIS:
+ if (sattr->index != 2)
+ reg = REG_REMOTE1_HYSTERSIS;
+ else
+ reg = REG_REMOTE2_HYSTERSIS;
+
+ break;
+ }
+
+ i2c_smbus_write_byte_data(client, reg, out);
+
+ mutex_unlock(&data->lock);
+ return count;
+}
+
+/* Table of autorange values - the user will write the value in millidegrees,
+ and we'll convert it */
+static const int autorange_table[] = {
+ 2000, 2500, 3330, 4000, 5000, 6670, 8000,
+ 10000, 13330, 16000, 20000, 26670, 32000, 40000,
+ 53330, 80000
+};
+
+static ssize_t show_point2(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct adt7475_data *data = adt7475_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int out, val;
+
+ mutex_lock(&data->lock);
+ out = (data->range[sattr->index] >> 4) & 0x0F;
+ val = reg2temp(data, data->temp[AUTOMIN][sattr->index]);
+ mutex_unlock(&data->lock);
+
+ return sprintf(buf, "%d\n", val + autorange_table[out]);
+}
+
+static ssize_t set_point2(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int temp;
+ long val;
+
+ if (strict_strtol(buf, 10, &val))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+
+ /* Get a fresh copy of the needed registers */
+ data->config5 = adt7475_read(REG_CONFIG5);
+ data->temp[AUTOMIN][sattr->index] =
+ adt7475_read(TEMP_TMIN_REG(sattr->index)) << 2;
+ data->range[sattr->index] =
+ adt7475_read(TEMP_TRANGE_REG(sattr->index));
+
+ /* The user will write an absolute value, so subtract the start point
+ to figure the range */
+ temp = reg2temp(data, data->temp[AUTOMIN][sattr->index]);
+ val = SENSORS_LIMIT(val, temp + autorange_table[0],
+ temp + autorange_table[ARRAY_SIZE(autorange_table) - 1]);
+ val -= temp;
+
+ /* Find the nearest table entry to what the user wrote */
+ val = find_nearest(val, autorange_table, ARRAY_SIZE(autorange_table));
+
+ data->range[sattr->index] &= ~0xF0;
+ data->range[sattr->index] |= val << 4;
+
+ i2c_smbus_write_byte_data(client, TEMP_TRANGE_REG(sattr->index),
+ data->range[sattr->index]);
+
+ mutex_unlock(&data->lock);
+ return count;
+}
+
+static ssize_t show_tach(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct adt7475_data *data = adt7475_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int out;
+
+ if (sattr->nr == ALARM)
+ out = (data->alarms >> (sattr->index + 10)) & 1;
+ else
+ out = tach2rpm(data->tach[sattr->nr][sattr->index]);
+
+ return sprintf(buf, "%d\n", out);
+}
+
+static ssize_t set_tach(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+
+ data->tach[MIN][sattr->index] = rpm2tach(val);
+
+ adt7475_write_word(client, TACH_MIN_REG(sattr->index),
+ data->tach[MIN][sattr->index]);
+
+ mutex_unlock(&data->lock);
+ return count;
+}
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct adt7475_data *data = adt7475_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+ return sprintf(buf, "%d\n", data->pwm[sattr->nr][sattr->index]);
+}
+
+static ssize_t show_pwmchan(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct adt7475_data *data = adt7475_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+ return sprintf(buf, "%d\n", data->pwmchan[sattr->index]);
+}
+
+static ssize_t show_pwmctrl(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct adt7475_data *data = adt7475_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+ return sprintf(buf, "%d\n", data->pwmctl[sattr->index]);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ unsigned char reg = 0;
+ long val;
+
+ if (strict_strtol(buf, 10, &val))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+
+ switch (sattr->nr) {
+ case INPUT:
+ /* Get a fresh value for CONTROL */
+ data->pwm[CONTROL][sattr->index] =
+ adt7475_read(PWM_CONFIG_REG(sattr->index));
+
+ /* If we are not in manual mode, then we shouldn't allow
+ * the user to set the pwm speed */
+ if (((data->pwm[CONTROL][sattr->index] >> 5) & 7) != 7) {
+ mutex_unlock(&data->lock);
+ return count;
+ }
+
+ reg = PWM_REG(sattr->index);
+ break;
+
+ case MIN:
+ reg = PWM_MIN_REG(sattr->index);
+ break;
+
+ case MAX:
+ reg = PWM_MAX_REG(sattr->index);
+ break;
+ }
+
+ data->pwm[sattr->nr][sattr->index] = SENSORS_LIMIT(val, 0, 0xFF);
+ i2c_smbus_write_byte_data(client, reg,
+ data->pwm[sattr->nr][sattr->index]);
+
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+/* Called by set_pwmctrl and set_pwmchan */
+
+static int hw_set_pwm(struct i2c_client *client, int index,
+ unsigned int pwmctl, unsigned int pwmchan)
+{
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ long val = 0;
+
+ switch (pwmctl) {
+ case 0:
+ val = 0x03; /* Run at full speed */
+ break;
+ case 1:
+ val = 0x07; /* Manual mode */
+ break;
+ case 2:
+ switch (pwmchan) {
+ case 1:
+ /* Remote1 controls PWM */
+ val = 0x00;
+ break;
+ case 2:
+ /* local controls PWM */
+ val = 0x01;
+ break;
+ case 4:
+ /* remote2 controls PWM */
+ val = 0x02;
+ break;
+ case 6:
+ /* local/remote2 control PWM */
+ val = 0x05;
+ break;
+ case 7:
+ /* All three control PWM */
+ val = 0x06;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ data->pwmctl[index] = pwmctl;
+ data->pwmchan[index] = pwmchan;
+
+ data->pwm[CONTROL][index] &= ~0xE0;
+ data->pwm[CONTROL][index] |= (val & 7) << 5;
+
+ i2c_smbus_write_byte_data(client, PWM_CONFIG_REG(index),
+ data->pwm[CONTROL][index]);
+
+ return 0;
+}
+
+static ssize_t set_pwmchan(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ int r;
+ long val;
+
+ if (strict_strtol(buf, 10, &val))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+ /* Read Modify Write PWM values */
+ adt7475_read_pwm(client, sattr->index);
+ r = hw_set_pwm(client, sattr->index, data->pwmctl[sattr->index], val);
+ if (r)
+ count = r;
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t set_pwmctrl(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ int r;
+ long val;
+
+ if (strict_strtol(buf, 10, &val))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+ /* Read Modify Write PWM values */
+ adt7475_read_pwm(client, sattr->index);
+ r = hw_set_pwm(client, sattr->index, val, data->pwmchan[sattr->index]);
+ if (r)
+ count = r;
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+/* List of frequencies for the PWM */
+static const int pwmfreq_table[] = {
+ 11, 14, 22, 29, 35, 44, 58, 88
+};
+
+static ssize_t show_pwmfreq(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct adt7475_data *data = adt7475_update_device(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+ return sprintf(buf, "%d\n",
+ pwmfreq_table[data->range[sattr->index] & 7]);
+}
+
+static ssize_t set_pwmfreq(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ int out;
+ long val;
+
+ if (strict_strtol(buf, 10, &val))
+ return -EINVAL;
+
+ out = find_nearest(val, pwmfreq_table, ARRAY_SIZE(pwmfreq_table));
+
+ mutex_lock(&data->lock);
+
+ data->range[sattr->index] =
+ adt7475_read(TEMP_TRANGE_REG(sattr->index));
+ data->range[sattr->index] &= ~7;
+ data->range[sattr->index] |= out;
+
+ i2c_smbus_write_byte_data(client, TEMP_TRANGE_REG(sattr->index),
+ data->range[sattr->index]);
+
+ mutex_unlock(&data->lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_voltage, NULL, INPUT, 0);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_voltage,
+ set_voltage, MAX, 0);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_voltage,
+ set_voltage, MIN, 0);
+static SENSOR_DEVICE_ATTR_2(in1_alarm, S_IRUGO, show_voltage, NULL, ALARM, 0);
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_voltage, NULL, INPUT, 1);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_voltage,
+ set_voltage, MAX, 1);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_voltage,
+ set_voltage, MIN, 1);
+static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, show_voltage, NULL, ALARM, 1);
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, INPUT, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_alarm, S_IRUGO, show_temp, NULL, ALARM, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_fault, S_IRUGO, show_temp, NULL, FAULT, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ MAX, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ MIN, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_offset, S_IRUGO | S_IWUSR, show_temp,
+ set_temp, OFFSET, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_point1_temp, S_IRUGO | S_IWUSR,
+ show_temp, set_temp, AUTOMIN, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_point2_temp, S_IRUGO | S_IWUSR,
+ show_point2, set_point2, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ THERM, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
+ set_temp, HYSTERSIS, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, INPUT, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_alarm, S_IRUGO, show_temp, NULL, ALARM, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ MAX, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ MIN, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IRUGO | S_IWUSR, show_temp,
+ set_temp, OFFSET, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_point1_temp, S_IRUGO | S_IWUSR,
+ show_temp, set_temp, AUTOMIN, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_point2_temp, S_IRUGO | S_IWUSR,
+ show_point2, set_point2, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ THERM, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
+ set_temp, HYSTERSIS, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, INPUT, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_alarm, S_IRUGO, show_temp, NULL, ALARM, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_temp, NULL, FAULT, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ MAX, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ MIN, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp,
+ set_temp, OFFSET, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_point1_temp, S_IRUGO | S_IWUSR,
+ show_temp, set_temp, AUTOMIN, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_point2_temp, S_IRUGO | S_IWUSR,
+ show_point2, set_point2, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ THERM, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
+ set_temp, HYSTERSIS, 2);
+static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_tach, NULL, INPUT, 0);
+static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_tach, set_tach,
+ MIN, 0);
+static SENSOR_DEVICE_ATTR_2(fan1_alarm, S_IRUGO, show_tach, NULL, ALARM, 0);
+static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_tach, NULL, INPUT, 1);
+static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_tach, set_tach,
+ MIN, 1);
+static SENSOR_DEVICE_ATTR_2(fan2_alarm, S_IRUGO, show_tach, NULL, ALARM, 1);
+static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_tach, NULL, INPUT, 2);
+static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_tach, set_tach,
+ MIN, 2);
+static SENSOR_DEVICE_ATTR_2(fan3_alarm, S_IRUGO, show_tach, NULL, ALARM, 2);
+static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_tach, NULL, INPUT, 3);
+static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_tach, set_tach,
+ MIN, 3);
+static SENSOR_DEVICE_ATTR_2(fan4_alarm, S_IRUGO, show_tach, NULL, ALARM, 3);
+static SENSOR_DEVICE_ATTR_2(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT,
+ 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_freq, S_IRUGO | S_IWUSR, show_pwmfreq,
+ set_pwmfreq, INPUT, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_enable, S_IRUGO | S_IWUSR, show_pwmctrl,
+ set_pwmctrl, INPUT, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_channel_temp, S_IRUGO | S_IWUSR,
+ show_pwmchan, set_pwmchan, INPUT, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
+ set_pwm, MIN, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
+ set_pwm, MAX, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT,
+ 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_freq, S_IRUGO | S_IWUSR, show_pwmfreq,
+ set_pwmfreq, INPUT, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_enable, S_IRUGO | S_IWUSR, show_pwmctrl,
+ set_pwmctrl, INPUT, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_channel_temp, S_IRUGO | S_IWUSR,
+ show_pwmchan, set_pwmchan, INPUT, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
+ set_pwm, MIN, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
+ set_pwm, MAX, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT,
+ 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_freq, S_IRUGO | S_IWUSR, show_pwmfreq,
+ set_pwmfreq, INPUT, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_enable, S_IRUGO | S_IWUSR, show_pwmctrl,
+ set_pwmctrl, INPUT, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_channel_temp, S_IRUGO | S_IWUSR,
+ show_pwmchan, set_pwmchan, INPUT, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
+ set_pwm, MIN, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
+ set_pwm, MAX, 2);
+
+static struct attribute *adt7475_attrs[] = {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_fault.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_offset.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_offset.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_offset.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_alarm.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm1_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_channel_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm2_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_channel_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm3_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_channel_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+ NULL,
+};
+
+struct attribute_group adt7475_attr_group = { .attrs = adt7475_attrs };
+
+static int adt7475_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = client->adapter;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ if (kind <= 0) {
+ if (adt7475_read(REG_VENDID) != 0x41 ||
+ adt7475_read(REG_DEVID) != 0x75) {
+ dev_err(&adapter->dev,
+ "Couldn't detect a adt7475 part at 0x%02x\n",
+ (unsigned int)client->addr);
+ return -ENODEV;
+ }
+ }
+
+ strlcpy(info->type, adt7475_id[0].name, I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int adt7475_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adt7475_data *data;
+ int i, ret = 0;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ mutex_init(&data->lock);
+ i2c_set_clientdata(client, data);
+
+ /* Call adt7475_read_pwm for all pwm's as this will reprogram any
+ pwm's which are disabled to manual mode with 0% duty cycle */
+ for (i = 0; i < ADT7475_PWM_COUNT; i++)
+ adt7475_read_pwm(client, i);
+
+ ret = sysfs_create_group(&client->dev.kobj, &adt7475_attr_group);
+ if (ret)
+ goto efree;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ goto eremove;
+ }
+
+ return 0;
+
+eremove:
+ sysfs_remove_group(&client->dev.kobj, &adt7475_attr_group);
+efree:
+ kfree(data);
+ return ret;
+}
+
+static int adt7475_remove(struct i2c_client *client)
+{
+ struct adt7475_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &adt7475_attr_group);
+ kfree(data);
+
+ return 0;
+}
+
+static struct i2c_driver adt7475_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "adt7475",
+ },
+ .probe = adt7475_probe,
+ .remove = adt7475_remove,
+ .id_table = adt7475_id,
+ .detect = adt7475_detect,
+ .address_data = &addr_data,
+};
+
+static void adt7475_read_hystersis(struct i2c_client *client)
+{
+ struct adt7475_data *data = i2c_get_clientdata(client);
+
+ data->temp[HYSTERSIS][0] = (u16) adt7475_read(REG_REMOTE1_HYSTERSIS);
+ data->temp[HYSTERSIS][1] = data->temp[HYSTERSIS][0];
+ data->temp[HYSTERSIS][2] = (u16) adt7475_read(REG_REMOTE2_HYSTERSIS);
+}
+
+static void adt7475_read_pwm(struct i2c_client *client, int index)
+{
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ unsigned int v;
+
+ data->pwm[CONTROL][index] = adt7475_read(PWM_CONFIG_REG(index));
+
+ /* Figure out the internal value for pwmctrl and pwmchan
+ based on the current settings */
+ v = (data->pwm[CONTROL][index] >> 5) & 7;
+
+ if (v == 3)
+ data->pwmctl[index] = 0;
+ else if (v == 7)
+ data->pwmctl[index] = 1;
+ else if (v == 4) {
+ /* The fan is disabled - we don't want to
+ support that, so change to manual mode and
+ set the duty cycle to 0 instead
+ */
+ data->pwm[INPUT][index] = 0;
+ data->pwm[CONTROL][index] &= ~0xE0;
+ data->pwm[CONTROL][index] |= (7 << 5);
+
+ i2c_smbus_write_byte_data(client, PWM_CONFIG_REG(index),
+ data->pwm[INPUT][index]);
+
+ i2c_smbus_write_byte_data(client, PWM_CONFIG_REG(index),
+ data->pwm[CONTROL][index]);
+
+ data->pwmctl[index] = 1;
+ } else {
+ data->pwmctl[index] = 2;
+
+ switch (v) {
+ case 0:
+ data->pwmchan[index] = 1;
+ break;
+ case 1:
+ data->pwmchan[index] = 2;
+ break;
+ case 2:
+ data->pwmchan[index] = 4;
+ break;
+ case 5:
+ data->pwmchan[index] = 6;
+ break;
+ case 6:
+ data->pwmchan[index] = 7;
+ break;
+ }
+ }
+}
+
+static struct adt7475_data *adt7475_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7475_data *data = i2c_get_clientdata(client);
+ u8 ext;
+ int i;
+
+ mutex_lock(&data->lock);
+
+ /* Measurement values update every 2 seconds */
+ if (time_after(jiffies, data->measure_updated + HZ * 2) ||
+ !data->valid) {
+ data->alarms = adt7475_read(REG_STATUS2) << 8;
+ data->alarms |= adt7475_read(REG_STATUS1);
+
+ ext = adt7475_read(REG_EXTEND1);
+ for (i = 0; i < ADT7475_VOLTAGE_COUNT; i++)
+ data->voltage[INPUT][i] =
+ (adt7475_read(VOLTAGE_REG(i)) << 2) |
+ ((ext >> ((i + 1) * 2)) & 3);
+
+ ext = adt7475_read(REG_EXTEND2);
+ for (i = 0; i < ADT7475_TEMP_COUNT; i++)
+ data->temp[INPUT][i] =
+ (adt7475_read(TEMP_REG(i)) << 2) |
+ ((ext >> ((i + 1) * 2)) & 3);
+
+ for (i = 0; i < ADT7475_TACH_COUNT; i++)
+ data->tach[INPUT][i] =
+ adt7475_read_word(client, TACH_REG(i));
+
+ /* Updated by hw when in auto mode */
+ for (i = 0; i < ADT7475_PWM_COUNT; i++)
+ data->pwm[INPUT][i] = adt7475_read(PWM_REG(i));
+
+ data->measure_updated = jiffies;
+ }
+
+ /* Limits and settings, should never change update every 60 seconds */
+ if (time_after(jiffies, data->limits_updated + HZ * 2) ||
+ !data->valid) {
+ data->config5 = adt7475_read(REG_CONFIG5);
+
+ for (i = 0; i < ADT7475_VOLTAGE_COUNT; i++) {
+ /* Adjust values so they match the input precision */
+ data->voltage[MIN][i] =
+ adt7475_read(VOLTAGE_MIN_REG(i)) << 2;
+ data->voltage[MAX][i] =
+ adt7475_read(VOLTAGE_MAX_REG(i)) << 2;
+ }
+
+ for (i = 0; i < ADT7475_TEMP_COUNT; i++) {
+ /* Adjust values so they match the input precision */
+ data->temp[MIN][i] =
+ adt7475_read(TEMP_MIN_REG(i)) << 2;
+ data->temp[MAX][i] =
+ adt7475_read(TEMP_MAX_REG(i)) << 2;
+ data->temp[AUTOMIN][i] =
+ adt7475_read(TEMP_TMIN_REG(i)) << 2;
+ data->temp[THERM][i] =
+ adt7475_read(TEMP_THERM_REG(i)) << 2;
+ data->temp[OFFSET][i] =
+ adt7475_read(TEMP_OFFSET_REG(i));
+ }
+ adt7475_read_hystersis(client);
+
+ for (i = 0; i < ADT7475_TACH_COUNT; i++)
+ data->tach[MIN][i] =
+ adt7475_read_word(client, TACH_MIN_REG(i));
+
+ for (i = 0; i < ADT7475_PWM_COUNT; i++) {
+ data->pwm[MAX][i] = adt7475_read(PWM_MAX_REG(i));
+ data->pwm[MIN][i] = adt7475_read(PWM_MIN_REG(i));
+ /* Set the channel and control information */
+ adt7475_read_pwm(client, i);
+ }
+
+ data->range[0] = adt7475_read(TEMP_TRANGE_REG(0));
+ data->range[1] = adt7475_read(TEMP_TRANGE_REG(1));
+ data->range[2] = adt7475_read(TEMP_TRANGE_REG(2));
+
+ data->limits_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->lock);
+
+ return data;
+}
+
+static int __init sensors_adt7475_init(void)
+{
+ return i2c_add_driver(&adt7475_driver);
+}
+
+static void __exit sensors_adt7475_exit(void)
+{
+ i2c_del_driver(&adt7475_driver);
+}
+
+MODULE_AUTHOR("Advanced Micro Devices, Inc");
+MODULE_DESCRIPTION("adt7475 driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_adt7475_init);
+module_exit(sensors_adt7475_exit);
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index dca47a591baf..e30186236588 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -590,6 +590,11 @@ static ssize_t applesmc_light_show(struct device *dev,
}
ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length);
+ /* newer macbooks report a single 10-bit bigendian value */
+ if (data_length == 10) {
+ left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2;
+ goto out;
+ }
left = buffer[2];
if (ret)
goto out;
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 8a45a2e6ba8a..8acf82977e7b 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -53,7 +53,10 @@ static const unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(asb100);
-I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
+
+static unsigned short force_subclients[4];
+module_param_array(force_subclients, short, NULL, 0);
+MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
/* Voltage IN registers 0-6 */
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index 27a5d397f9a1..3df202a9ad72 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -34,6 +34,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/acpi.h>
#include <asm/io.h>
/* ISA device, if found */
@@ -2361,6 +2362,10 @@ static int __init dme1737_isa_device_add(unsigned short addr)
};
int err;
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto exit;
+
if (!(pdev = platform_device_alloc("dme1737", addr))) {
printk(KERN_ERR "dme1737: Failed to allocate device.\n");
err = -ENOMEM;
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 7a14a2dbb752..899876579253 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -39,6 +39,7 @@
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/ioport.h>
+#include <linux/acpi.h>
#include <asm/io.h>
static unsigned short force_id;
@@ -1455,6 +1456,10 @@ static int __init f71805f_device_add(unsigned short address,
}
res.name = pdev->name;
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto exit_device_put;
+
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
printk(KERN_ERR DRVNAME ": Device resource addition failed "
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index 67067e9a323e..609cafff86bc 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -1,6 +1,6 @@
/***************************************************************************
* Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
- * Copyright (C) 2007 by Hans de Goede <j.w.r.degoede@hhs.nl> *
+ * Copyright (C) 2007,2008 by Hans de Goede <hdegoede@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 *
@@ -27,11 +27,12 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
-#include <asm/io.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
#define DRVNAME "f71882fg"
-#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device*/
+#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */
@@ -43,7 +44,9 @@
#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
+#define SIO_F71862_ID 0x0601 /* Chipset ID */
#define SIO_F71882_ID 0x0541 /* Chipset ID */
+#define SIO_F8000_ID 0x0581 /* Chipset ID */
#define REGION_LENGTH 8
#define ADDR_REG_OFFSET 5
@@ -51,25 +54,36 @@
#define F71882FG_REG_PECI 0x0A
-#define F71882FG_REG_IN_STATUS 0x12
-#define F71882FG_REG_IN_BEEP 0x13
+#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
+#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
#define F71882FG_REG_IN(nr) (0x20 + (nr))
-#define F71882FG_REG_IN1_HIGH 0x32
+#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
+#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
+#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
#define F71882FG_REG_FAN_STATUS 0x92
#define F71882FG_REG_FAN_BEEP 0x93
-#define F71882FG_REG_TEMP(nr) (0x72 + 2 * (nr))
-#define F71882FG_REG_TEMP_OVT(nr) (0x82 + 2 * (nr))
-#define F71882FG_REG_TEMP_HIGH(nr) (0x83 + 2 * (nr))
+#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
+#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
+#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
#define F71882FG_REG_TEMP_STATUS 0x62
#define F71882FG_REG_TEMP_BEEP 0x63
-#define F71882FG_REG_TEMP_HYST1 0x6C
-#define F71882FG_REG_TEMP_HYST23 0x6D
+#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
#define F71882FG_REG_TEMP_TYPE 0x6B
#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
+#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
+#define F71882FG_REG_PWM_TYPE 0x94
+#define F71882FG_REG_PWM_ENABLE 0x96
+
+#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
+
+#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
+#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
+#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
+
#define F71882FG_REG_START 0x01
#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
@@ -78,7 +92,15 @@ static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
-static struct platform_device *f71882fg_pdev = NULL;
+enum chips { f71862fg, f71882fg, f8000 };
+
+static const char *f71882fg_names[] = {
+ "f71862fg",
+ "f71882fg",
+ "f8000",
+};
+
+static struct platform_device *f71882fg_pdev;
/* Super-I/O Function prototypes */
static inline int superio_inb(int base, int reg);
@@ -87,8 +109,13 @@ static inline void superio_enter(int base);
static inline void superio_select(int base, int ld);
static inline void superio_exit(int base);
+struct f71882fg_sio_data {
+ enum chips type;
+};
+
struct f71882fg_data {
unsigned short addr;
+ enum chips type;
struct device *hwmon_dev;
struct mutex update_lock;
@@ -102,19 +129,30 @@ struct f71882fg_data {
u8 in_status;
u8 in_beep;
u16 fan[4];
+ u16 fan_target[4];
+ u16 fan_full_speed[4];
u8 fan_status;
u8 fan_beep;
- u8 temp[3];
- u8 temp_ovt[3];
- u8 temp_high[3];
- u8 temp_hyst[3];
- u8 temp_type[3];
+ /* Note: all models have only 3 temperature channels, but on some
+ they are addressed as 0-2 and on others as 1-3, so for coding
+ convenience we reserve space for 4 channels */
+ u8 temp[4];
+ u8 temp_ovt[4];
+ u8 temp_high[4];
+ u8 temp_hyst[2]; /* 2 hysts stored per reg */
+ u8 temp_type[4];
u8 temp_status;
u8 temp_beep;
u8 temp_diode_open;
+ u8 pwm[4];
+ u8 pwm_enable;
+ u8 pwm_auto_point_hyst[2];
+ u8 pwm_auto_point_mapping[4];
+ u8 pwm_auto_point_pwm[4][5];
+ u8 pwm_auto_point_temp[4][4];
};
-/* Sysfs in*/
+/* Sysfs in */
static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
char *buf);
static ssize_t show_in_max(struct device *dev, struct device_attribute
@@ -130,6 +168,10 @@ static ssize_t show_in_alarm(struct device *dev, struct device_attribute
/* Sysfs Fan */
static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
char *buf);
+static ssize_t show_fan_full_speed(struct device *dev,
+ struct device_attribute *devattr, char *buf);
+static ssize_t store_fan_full_speed(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count);
static ssize_t show_fan_beep(struct device *dev, struct device_attribute
*devattr, char *buf);
static ssize_t store_fan_beep(struct device *dev, struct device_attribute
@@ -163,16 +205,41 @@ static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
*devattr, char *buf);
static ssize_t show_temp_fault(struct device *dev, struct device_attribute
*devattr, char *buf);
+/* PWM and Auto point control */
+static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
+ char *buf);
+static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count);
+static ssize_t show_pwm_enable(struct device *dev,
+ struct device_attribute *devattr, char *buf);
+static ssize_t store_pwm_enable(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count);
+static ssize_t show_pwm_interpolate(struct device *dev,
+ struct device_attribute *devattr, char *buf);
+static ssize_t store_pwm_interpolate(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count);
+static ssize_t show_pwm_auto_point_channel(struct device *dev,
+ struct device_attribute *devattr, char *buf);
+static ssize_t store_pwm_auto_point_channel(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count);
+static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
+ struct device_attribute *devattr, char *buf);
+static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count);
+static ssize_t show_pwm_auto_point_pwm(struct device *dev,
+ struct device_attribute *devattr, char *buf);
+static ssize_t store_pwm_auto_point_pwm(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count);
+static ssize_t show_pwm_auto_point_temp(struct device *dev,
+ struct device_attribute *devattr, char *buf);
+static ssize_t store_pwm_auto_point_temp(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count);
/* Sysfs misc */
static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
char *buf);
static int __devinit f71882fg_probe(struct platform_device * pdev);
-static int __devexit f71882fg_remove(struct platform_device *pdev);
-static int __init f71882fg_init(void);
-static int __init f71882fg_find(int sioaddr, unsigned short *address);
-static int __init f71882fg_device_add(unsigned short address);
-static void __exit f71882fg_exit(void);
+static int f71882fg_remove(struct platform_device *pdev);
static struct platform_driver f71882fg_driver = {
.driver = {
@@ -183,86 +250,531 @@ static struct platform_driver f71882fg_driver = {
.remove = __devexit_p(f71882fg_remove),
};
-static struct device_attribute f71882fg_dev_attr[] =
-{
- __ATTR( name, S_IRUGO, show_name, NULL ),
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+/* Temp and in attr common to both the f71862fg and f71882fg */
+static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = {
+ SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
+ SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
+ SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
+ SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
+ SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
+ SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
+ SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
+ SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
+ SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
+ SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
+ SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 0, 1),
+ SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 0, 1),
+ /* Should really be temp1_max_alarm, but older versions did not handle
+ the max and crit alarms separately and lm_sensors v2 depends on the
+ presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
+ SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
+ SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0, 1),
+ SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 0, 1),
+ SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+ 0, 1),
+ SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
+ SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0, 5),
+ SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
+ SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
+ SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
+ SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 0, 2),
+ SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 0, 2),
+ /* Should be temp2_max_alarm, see temp1_alarm note */
+ SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
+ SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0, 2),
+ SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 0, 2),
+ SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+ 0, 2),
+ SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
+ SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0, 6),
+ SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
+ SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
+ SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
+ SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 0, 3),
+ SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+ store_temp_max_hyst, 0, 3),
+ /* Should be temp3_max_alarm, see temp1_alarm note */
+ SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
+ SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0, 3),
+ SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 0, 3),
+ SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+ 0, 3),
+ SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
+ SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
+ store_temp_beep, 0, 7),
+ SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
+ SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
+};
+
+/* Temp and in attr found only on the f71882fg */
+static struct sensor_device_attribute_2 f71882fg_in_temp_attr[] = {
+ SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
+ 0, 1),
+ SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
+ 0, 1),
+ SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
+};
+
+/* Temp and in attr for the f8000
+ Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
+ is used as hysteresis value to clear alarms
+ */
+static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
+ SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
+ SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
+ SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
+ SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
+ SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 0, 0),
+ SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 0, 0),
+ SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
+ SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
+ SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 0, 1),
+ SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 0, 1),
+ SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
+ SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
+ SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
+ SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
+ store_temp_crit, 0, 2),
+ SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
+ store_temp_max, 0, 2),
+ SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
+};
+
+/* Fan / PWM attr common to all models */
+static struct sensor_device_attribute_2 fxxxx_fan_attr[] = {
+ SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
+ SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
+ show_fan_full_speed,
+ store_fan_full_speed, 0, 0),
+ SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
+ SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
+ SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
+ show_fan_full_speed,
+ store_fan_full_speed, 0, 1),
+ SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
+ SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
+ SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
+ show_fan_full_speed,
+ store_fan_full_speed, 0, 2),
+ SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
+
+ SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
+ SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+ store_pwm_enable, 0, 0),
+ SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
+ show_pwm_interpolate, store_pwm_interpolate, 0, 0),
+ SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_channel,
+ store_pwm_auto_point_channel, 0, 0),
+
+ SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
+ SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+ store_pwm_enable, 0, 1),
+ SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
+ show_pwm_interpolate, store_pwm_interpolate, 0, 1),
+ SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_channel,
+ store_pwm_auto_point_channel, 0, 1),
+
+ SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
+ show_pwm_interpolate, store_pwm_interpolate, 0, 2),
+ SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_channel,
+ store_pwm_auto_point_channel, 0, 2),
};
-static struct sensor_device_attribute f71882fg_in_temp_attr[] =
-{
- SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
- SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
- SENSOR_ATTR(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max, 1),
- SENSOR_ATTR(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep, 1),
- SENSOR_ATTR(in1_alarm, S_IRUGO, show_in_alarm, NULL, 1),
- SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
- SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
- SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
- SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
- SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
- SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
- SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
- SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
- SENSOR_ATTR(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
- store_temp_max, 0),
- SENSOR_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
- store_temp_max_hyst, 0),
- SENSOR_ATTR(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
- store_temp_crit, 0),
- SENSOR_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 0),
- SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
- SENSOR_ATTR(temp1_beep, S_IRUGO|S_IWUSR, show_temp_beep,
- store_temp_beep, 0),
- SENSOR_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0),
- SENSOR_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0),
- SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
- SENSOR_ATTR(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
- store_temp_max, 1),
- SENSOR_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
- store_temp_max_hyst, 1),
- SENSOR_ATTR(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
- store_temp_crit, 1),
- SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1),
- SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
- SENSOR_ATTR(temp2_beep, S_IRUGO|S_IWUSR, show_temp_beep,
- store_temp_beep, 1),
- SENSOR_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 1),
- SENSOR_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1),
- SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
- SENSOR_ATTR(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
- store_temp_max, 2),
- SENSOR_ATTR(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
- store_temp_max_hyst, 2),
- SENSOR_ATTR(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
- store_temp_crit, 2),
- SENSOR_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 2),
- SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
- SENSOR_ATTR(temp3_beep, S_IRUGO|S_IWUSR, show_temp_beep,
- store_temp_beep, 2),
- SENSOR_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 2),
- SENSOR_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2)
+/* Fan / PWM attr for the f71862fg, less pwms and less zones per pwm than the
+ f71882fg */
+static struct sensor_device_attribute_2 f71862fg_fan_attr[] = {
+ SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 0, 0),
+ SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 0, 1),
+ SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 0, 2),
+
+ SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 1, 0),
+ SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 4, 0),
+ SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 0, 0),
+ SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 3, 0),
+ SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp_hyst,
+ store_pwm_auto_point_temp_hyst,
+ 0, 0),
+ SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 3, 0),
+
+ SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 1, 1),
+ SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 4, 1),
+ SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 0, 1),
+ SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 3, 1),
+ SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp_hyst,
+ store_pwm_auto_point_temp_hyst,
+ 0, 1),
+ SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 3, 1),
+
+ SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
+ SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+ store_pwm_enable, 0, 2),
+ SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 1, 2),
+ SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 4, 2),
+ SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 0, 2),
+ SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 3, 2),
+ SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp_hyst,
+ store_pwm_auto_point_temp_hyst,
+ 0, 2),
+ SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 3, 2),
};
-static struct sensor_device_attribute f71882fg_fan_attr[] =
-{
- SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
- SENSOR_ATTR(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
- store_fan_beep, 0),
- SENSOR_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0),
- SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
- SENSOR_ATTR(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
- store_fan_beep, 1),
- SENSOR_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 1),
- SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
- SENSOR_ATTR(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
- store_fan_beep, 2),
- SENSOR_ATTR(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 2),
- SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
- SENSOR_ATTR(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
- store_fan_beep, 3),
- SENSOR_ATTR(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 3)
+/* Fan / PWM attr for the f71882fg */
+static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
+ SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 0, 0),
+ SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 0, 1),
+ SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 0, 2),
+ SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
+ SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
+ show_fan_full_speed,
+ store_fan_full_speed, 0, 3),
+ SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+ store_fan_beep, 0, 3),
+ SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
+
+ SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 0, 0),
+ SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 1, 0),
+ SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 2, 0),
+ SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 3, 0),
+ SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 4, 0),
+ SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 0, 0),
+ SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 1, 0),
+ SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 2, 0),
+ SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 3, 0),
+ SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp_hyst,
+ store_pwm_auto_point_temp_hyst,
+ 0, 0),
+ SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 1, 0),
+ SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 2, 0),
+ SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 3, 0),
+
+ SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 0, 1),
+ SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 1, 1),
+ SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 2, 1),
+ SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 3, 1),
+ SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 4, 1),
+ SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 0, 1),
+ SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 1, 1),
+ SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 2, 1),
+ SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 3, 1),
+ SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp_hyst,
+ store_pwm_auto_point_temp_hyst,
+ 0, 1),
+ SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 1, 1),
+ SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 2, 1),
+ SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 3, 1),
+
+ SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
+ SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+ store_pwm_enable, 0, 2),
+ SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 0, 2),
+ SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 1, 2),
+ SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 2, 2),
+ SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 3, 2),
+ SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 4, 2),
+ SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 0, 2),
+ SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 1, 2),
+ SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 2, 2),
+ SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 3, 2),
+ SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp_hyst,
+ store_pwm_auto_point_temp_hyst,
+ 0, 2),
+ SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 1, 2),
+ SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 2, 2),
+ SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 3, 2),
+
+ SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
+ SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+ store_pwm_enable, 0, 3),
+ SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
+ show_pwm_interpolate, store_pwm_interpolate, 0, 3),
+ SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_channel,
+ store_pwm_auto_point_channel, 0, 3),
+ SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 0, 3),
+ SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 1, 3),
+ SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 2, 3),
+ SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 3, 3),
+ SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 4, 3),
+ SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 0, 3),
+ SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 1, 3),
+ SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 2, 3),
+ SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 3, 3),
+ SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp_hyst,
+ store_pwm_auto_point_temp_hyst,
+ 0, 3),
+ SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 1, 3),
+ SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 2, 3),
+ SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 3, 3),
};
+/* Fan / PWM attr for the f8000, zones mapped to temp instead of to pwm!
+ Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
+ F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
+static struct sensor_device_attribute_2 f8000_fan_attr[] = {
+ SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
+
+ SENSOR_ATTR_2(pwm3, S_IRUGO, show_pwm, NULL, 0, 2),
+
+ SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 0, 2),
+ SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 1, 2),
+ SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 2, 2),
+ SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 3, 2),
+ SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 4, 2),
+ SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 0, 2),
+ SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 1, 2),
+ SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 2, 2),
+ SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 3, 2),
+ SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp_hyst,
+ store_pwm_auto_point_temp_hyst,
+ 0, 2),
+ SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 1, 2),
+ SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 2, 2),
+ SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 3, 2),
+
+ SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 0, 0),
+ SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 1, 0),
+ SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 2, 0),
+ SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 3, 0),
+ SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 4, 0),
+ SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 0, 0),
+ SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 1, 0),
+ SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 2, 0),
+ SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 3, 0),
+ SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp_hyst,
+ store_pwm_auto_point_temp_hyst,
+ 0, 0),
+ SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 1, 0),
+ SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 2, 0),
+ SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 3, 0),
+
+ SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 0, 1),
+ SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 1, 1),
+ SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 2, 1),
+ SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 3, 1),
+ SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
+ 4, 1),
+ SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 0, 1),
+ SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 1, 1),
+ SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 2, 1),
+ SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp, store_pwm_auto_point_temp,
+ 3, 1),
+ SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
+ show_pwm_auto_point_temp_hyst,
+ store_pwm_auto_point_temp_hyst,
+ 0, 1),
+ SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 1, 1),
+ SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 2, 1),
+ SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
+ show_pwm_auto_point_temp_hyst, NULL, 3, 1),
+};
/* Super I/O functions */
static inline int superio_inb(int base, int reg)
@@ -299,11 +811,16 @@ static inline void superio_exit(int base)
outb(SIO_LOCK_KEY, base);
}
-static inline u16 fan_from_reg(u16 reg)
+static inline int fan_from_reg(u16 reg)
{
return reg ? (1500000 / reg) : 0;
}
+static inline u16 fan_to_reg(int fan)
+{
+ return fan ? (1500000 / fan) : 0;
+}
+
static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
{
u8 val;
@@ -332,52 +849,111 @@ static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
outb(val, data->addr + DATA_REG_OFFSET);
}
-static struct f71882fg_data *f71882fg_update_device(struct device * dev)
+static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
+{
+ outb(reg++, data->addr + ADDR_REG_OFFSET);
+ outb(val >> 8, data->addr + DATA_REG_OFFSET);
+ outb(reg, data->addr + ADDR_REG_OFFSET);
+ outb(val & 255, data->addr + DATA_REG_OFFSET);
+}
+
+static struct f71882fg_data *f71882fg_update_device(struct device *dev)
{
struct f71882fg_data *data = dev_get_drvdata(dev);
- int nr, reg, reg2;
+ int nr, reg = 0, reg2;
+ int nr_fans = (data->type == f71882fg) ? 4 : 3;
+ int nr_ins = (data->type == f8000) ? 3 : 9;
+ int temp_start = (data->type == f8000) ? 0 : 1;
mutex_lock(&data->update_lock);
/* Update once every 60 seconds */
if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
!data->valid) {
- data->in1_max = f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
- data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
+ if (data->type == f71882fg) {
+ data->in1_max =
+ f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
+ data->in_beep =
+ f71882fg_read8(data, F71882FG_REG_IN_BEEP);
+ }
/* Get High & boundary temps*/
- for (nr = 0; nr < 3; nr++) {
+ for (nr = temp_start; nr < 3 + temp_start; nr++) {
data->temp_ovt[nr] = f71882fg_read8(data,
F71882FG_REG_TEMP_OVT(nr));
data->temp_high[nr] = f71882fg_read8(data,
F71882FG_REG_TEMP_HIGH(nr));
}
- /* Have to hardcode hyst*/
- data->temp_hyst[0] = f71882fg_read8(data,
- F71882FG_REG_TEMP_HYST1) >> 4;
- /* Hyst temps 2 & 3 stored in same register */
- reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST23);
- data->temp_hyst[1] = reg & 0x0F;
- data->temp_hyst[2] = reg >> 4;
-
- /* Have to hardcode type, because temp1 is special */
- reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
+ if (data->type != f8000) {
+ data->fan_beep = f71882fg_read8(data,
+ F71882FG_REG_FAN_BEEP);
+ data->temp_beep = f71882fg_read8(data,
+ F71882FG_REG_TEMP_BEEP);
+ data->temp_hyst[0] = f71882fg_read8(data,
+ F71882FG_REG_TEMP_HYST(0));
+ data->temp_hyst[1] = f71882fg_read8(data,
+ F71882FG_REG_TEMP_HYST(1));
+ /* Have to hardcode type, because temp1 is special */
+ reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
+ data->temp_type[2] = (reg & 0x04) ? 2 : 4;
+ data->temp_type[3] = (reg & 0x08) ? 2 : 4;
+ }
reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
if ((reg2 & 0x03) == 0x01)
- data->temp_type[0] = 6 /* PECI */;
+ data->temp_type[1] = 6 /* PECI */;
else if ((reg2 & 0x03) == 0x02)
- data->temp_type[0] = 5 /* AMDSI */;
+ data->temp_type[1] = 5 /* AMDSI */;
+ else if (data->type != f8000)
+ data->temp_type[1] = (reg & 0x02) ? 2 : 4;
else
- data->temp_type[0] = (reg & 0x02) ? 2 : 4;
-
- data->temp_type[1] = (reg & 0x04) ? 2 : 4;
- data->temp_type[2] = (reg & 0x08) ? 2 : 4;
-
- data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
-
- data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
-
+ data->temp_type[1] = 2; /* F8000 only supports BJT */
+
+ data->pwm_enable = f71882fg_read8(data,
+ F71882FG_REG_PWM_ENABLE);
+ data->pwm_auto_point_hyst[0] =
+ f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
+ data->pwm_auto_point_hyst[1] =
+ f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
+
+ for (nr = 0; nr < nr_fans; nr++) {
+ data->pwm_auto_point_mapping[nr] =
+ f71882fg_read8(data,
+ F71882FG_REG_POINT_MAPPING(nr));
+
+ if (data->type != f71862fg) {
+ int point;
+ for (point = 0; point < 5; point++) {
+ data->pwm_auto_point_pwm[nr][point] =
+ f71882fg_read8(data,
+ F71882FG_REG_POINT_PWM
+ (nr, point));
+ }
+ for (point = 0; point < 4; point++) {
+ data->pwm_auto_point_temp[nr][point] =
+ f71882fg_read8(data,
+ F71882FG_REG_POINT_TEMP
+ (nr, point));
+ }
+ } else {
+ data->pwm_auto_point_pwm[nr][1] =
+ f71882fg_read8(data,
+ F71882FG_REG_POINT_PWM
+ (nr, 1));
+ data->pwm_auto_point_pwm[nr][4] =
+ f71882fg_read8(data,
+ F71882FG_REG_POINT_PWM
+ (nr, 4));
+ data->pwm_auto_point_temp[nr][0] =
+ f71882fg_read8(data,
+ F71882FG_REG_POINT_TEMP
+ (nr, 0));
+ data->pwm_auto_point_temp[nr][3] =
+ f71882fg_read8(data,
+ F71882FG_REG_POINT_TEMP
+ (nr, 3));
+ }
+ }
data->last_limits = jiffies;
}
@@ -387,19 +963,32 @@ static struct f71882fg_data *f71882fg_update_device(struct device * dev)
F71882FG_REG_TEMP_STATUS);
data->temp_diode_open = f71882fg_read8(data,
F71882FG_REG_TEMP_DIODE_OPEN);
- for (nr = 0; nr < 3; nr++)
+ for (nr = temp_start; nr < 3 + temp_start; nr++)
data->temp[nr] = f71882fg_read8(data,
F71882FG_REG_TEMP(nr));
data->fan_status = f71882fg_read8(data,
F71882FG_REG_FAN_STATUS);
- for (nr = 0; nr < 4; nr++)
+ for (nr = 0; nr < nr_fans; nr++) {
data->fan[nr] = f71882fg_read16(data,
F71882FG_REG_FAN(nr));
+ data->fan_target[nr] =
+ f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
+ data->fan_full_speed[nr] =
+ f71882fg_read16(data,
+ F71882FG_REG_FAN_FULL_SPEED(nr));
+ data->pwm[nr] =
+ f71882fg_read8(data, F71882FG_REG_PWM(nr));
+ }
- data->in_status = f71882fg_read8(data,
+ /* The f8000 can monitor 1 more fan, but has no pwm for it */
+ if (data->type == f8000)
+ data->fan[3] = f71882fg_read16(data,
+ F71882FG_REG_FAN(3));
+ if (data->type == f71882fg)
+ data->in_status = f71882fg_read8(data,
F71882FG_REG_IN_STATUS);
- for (nr = 0; nr < 9; nr++)
+ for (nr = 0; nr < nr_ins; nr++)
data->in[nr] = f71882fg_read8(data,
F71882FG_REG_IN(nr));
@@ -417,7 +1006,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
int speed = fan_from_reg(data->fan[nr]);
if (speed == FAN_MIN_DETECT)
@@ -426,11 +1015,39 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
return sprintf(buf, "%d\n", speed);
}
+static ssize_t show_fan_full_speed(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ int speed = fan_from_reg(data->fan_full_speed[nr]);
+ return sprintf(buf, "%d\n", speed);
+}
+
+static ssize_t store_fan_full_speed(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ long val = simple_strtol(buf, NULL, 10);
+
+ val = SENSORS_LIMIT(val, 23, 1500000);
+ val = fan_to_reg(val);
+
+ mutex_lock(&data->update_lock);
+ f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
+ data->fan_full_speed[nr] = val;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
static ssize_t show_fan_beep(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
if (data->fan_beep & (1 << nr))
return sprintf(buf, "1\n");
@@ -442,10 +1059,11 @@ static ssize_t store_fan_beep(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count)
{
struct f71882fg_data *data = dev_get_drvdata(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
- int val = simple_strtoul(buf, NULL, 10);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
+ data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
if (val)
data->fan_beep |= 1 << nr;
else
@@ -461,7 +1079,7 @@ static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
if (data->fan_status & (1 << nr))
return sprintf(buf, "1\n");
@@ -473,7 +1091,7 @@ static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
return sprintf(buf, "%d\n", data->in[nr] * 8);
}
@@ -490,10 +1108,8 @@ static ssize_t store_in_max(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count)
{
struct f71882fg_data *data = dev_get_drvdata(dev);
- int val = simple_strtoul(buf, NULL, 10) / 8;
-
- if (val > 255)
- val = 255;
+ long val = simple_strtol(buf, NULL, 10) / 8;
+ val = SENSORS_LIMIT(val, 0, 255);
mutex_lock(&data->update_lock);
f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
@@ -507,7 +1123,7 @@ static ssize_t show_in_beep(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
if (data->in_beep & (1 << nr))
return sprintf(buf, "1\n");
@@ -519,10 +1135,11 @@ static ssize_t store_in_beep(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count)
{
struct f71882fg_data *data = dev_get_drvdata(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
- int val = simple_strtoul(buf, NULL, 10);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
+ data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
if (val)
data->in_beep |= 1 << nr;
else
@@ -538,7 +1155,7 @@ static ssize_t show_in_alarm(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
if (data->in_status & (1 << nr))
return sprintf(buf, "1\n");
@@ -550,7 +1167,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
return sprintf(buf, "%d\n", data->temp[nr] * 1000);
}
@@ -559,7 +1176,7 @@ static ssize_t show_temp_max(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
}
@@ -568,11 +1185,9 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count)
{
struct f71882fg_data *data = dev_get_drvdata(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
- int val = simple_strtoul(buf, NULL, 10) / 1000;
-
- if (val > 255)
- val = 255;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ long val = simple_strtol(buf, NULL, 10) / 1000;
+ val = SENSORS_LIMIT(val, 0, 255);
mutex_lock(&data->update_lock);
f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
@@ -586,48 +1201,46 @@ static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ int temp_max_hyst;
+
+ mutex_lock(&data->update_lock);
+ if (nr & 1)
+ temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
+ else
+ temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
+ temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
+ mutex_unlock(&data->update_lock);
- return sprintf(buf, "%d\n",
- (data->temp_high[nr] - data->temp_hyst[nr]) * 1000);
+ return sprintf(buf, "%d\n", temp_max_hyst);
}
static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count)
{
struct f71882fg_data *data = dev_get_drvdata(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
- int val = simple_strtoul(buf, NULL, 10) / 1000;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ long val = simple_strtol(buf, NULL, 10) / 1000;
ssize_t ret = count;
+ u8 reg;
mutex_lock(&data->update_lock);
/* convert abs to relative and check */
+ data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
+ val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
+ data->temp_high[nr]);
val = data->temp_high[nr] - val;
- if (val < 0 || val > 15) {
- ret = -EINVAL;
- goto store_temp_max_hyst_exit;
- }
-
- data->temp_hyst[nr] = val;
/* convert value to register contents */
- switch (nr) {
- case 0:
- val = val << 4;
- break;
- case 1:
- val = val | (data->temp_hyst[2] << 4);
- break;
- case 2:
- val = data->temp_hyst[1] | (val << 4);
- break;
- }
-
- f71882fg_write8(data, nr ? F71882FG_REG_TEMP_HYST23 :
- F71882FG_REG_TEMP_HYST1, val);
+ reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
+ if (nr & 1)
+ reg = (reg & 0x0f) | (val << 4);
+ else
+ reg = (reg & 0xf0) | val;
+ f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
+ data->temp_hyst[nr / 2] = reg;
-store_temp_max_hyst_exit:
mutex_unlock(&data->update_lock);
return ret;
}
@@ -636,7 +1249,7 @@ static ssize_t show_temp_crit(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
}
@@ -645,11 +1258,9 @@ static ssize_t store_temp_crit(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count)
{
struct f71882fg_data *data = dev_get_drvdata(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
- int val = simple_strtoul(buf, NULL, 10) / 1000;
-
- if (val > 255)
- val = 255;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ long val = simple_strtol(buf, NULL, 10) / 1000;
+ val = SENSORS_LIMIT(val, 0, 255);
mutex_lock(&data->update_lock);
f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
@@ -663,17 +1274,25 @@ static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ int temp_crit_hyst;
+
+ mutex_lock(&data->update_lock);
+ if (nr & 1)
+ temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
+ else
+ temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
+ temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
+ mutex_unlock(&data->update_lock);
- return sprintf(buf, "%d\n",
- (data->temp_ovt[nr] - data->temp_hyst[nr]) * 1000);
+ return sprintf(buf, "%d\n", temp_crit_hyst);
}
static ssize_t show_temp_type(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
return sprintf(buf, "%d\n", data->temp_type[nr]);
}
@@ -682,9 +1301,9 @@ static ssize_t show_temp_beep(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
- if (data->temp_beep & (1 << (nr + 1)))
+ if (data->temp_beep & (1 << nr))
return sprintf(buf, "1\n");
else
return sprintf(buf, "0\n");
@@ -694,14 +1313,15 @@ static ssize_t store_temp_beep(struct device *dev, struct device_attribute
*devattr, const char *buf, size_t count)
{
struct f71882fg_data *data = dev_get_drvdata(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
- int val = simple_strtoul(buf, NULL, 10);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
+ data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
if (val)
- data->temp_beep |= 1 << (nr + 1);
+ data->temp_beep |= 1 << nr;
else
- data->temp_beep &= ~(1 << (nr + 1));
+ data->temp_beep &= ~(1 << nr);
f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
mutex_unlock(&data->update_lock);
@@ -713,9 +1333,9 @@ static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
- if (data->temp_status & (1 << (nr + 1)))
+ if (data->temp_status & (1 << nr))
return sprintf(buf, "1\n");
else
return sprintf(buf, "0\n");
@@ -725,113 +1345,528 @@ static ssize_t show_temp_fault(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct f71882fg_data *data = f71882fg_update_device(dev);
- int nr = to_sensor_dev_attr(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->index;
- if (data->temp_diode_open & (1 << (nr + 1)))
+ if (data->temp_diode_open & (1 << nr))
return sprintf(buf, "1\n");
else
return sprintf(buf, "0\n");
}
+static ssize_t show_pwm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int val, nr = to_sensor_dev_attr_2(devattr)->index;
+ mutex_lock(&data->update_lock);
+ if (data->pwm_enable & (1 << (2 * nr)))
+ /* PWM mode */
+ val = data->pwm[nr];
+ else {
+ /* RPM mode */
+ val = 255 * fan_from_reg(data->fan_target[nr])
+ / fan_from_reg(data->fan_full_speed[nr]);
+ }
+ mutex_unlock(&data->update_lock);
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t store_pwm(struct device *dev,
+ struct device_attribute *devattr, const char *buf,
+ size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ long val = simple_strtol(buf, NULL, 10);
+ val = SENSORS_LIMIT(val, 0, 255);
+
+ mutex_lock(&data->update_lock);
+ data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
+ if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
+ (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
+ count = -EROFS;
+ goto leave;
+ }
+ if (data->pwm_enable & (1 << (2 * nr))) {
+ /* PWM mode */
+ f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
+ data->pwm[nr] = val;
+ } else {
+ /* RPM mode */
+ int target, full_speed;
+ full_speed = f71882fg_read16(data,
+ F71882FG_REG_FAN_FULL_SPEED(nr));
+ target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
+ f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
+ data->fan_target[nr] = target;
+ data->fan_full_speed[nr] = full_speed;
+ }
+leave:
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_enable(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int result = 0;
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+
+ switch ((data->pwm_enable >> 2 * nr) & 3) {
+ case 0:
+ case 1:
+ result = 2; /* Normal auto mode */
+ break;
+ case 2:
+ result = 1; /* Manual mode */
+ break;
+ case 3:
+ if (data->type == f8000)
+ result = 3; /* Thermostat mode */
+ else
+ result = 1; /* Manual mode */
+ break;
+ }
+
+ return sprintf(buf, "%d\n", result);
+}
+
+static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
+ /* Special case for F8000 auto PWM mode / Thermostat mode */
+ if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
+ switch (val) {
+ case 2:
+ data->pwm_enable &= ~(2 << (2 * nr));
+ break; /* Normal auto mode */
+ case 3:
+ data->pwm_enable |= 2 << (2 * nr);
+ break; /* Thermostat mode */
+ default:
+ count = -EINVAL;
+ goto leave;
+ }
+ } else {
+ switch (val) {
+ case 1:
+ data->pwm_enable |= 2 << (2 * nr);
+ break; /* Manual */
+ case 2:
+ data->pwm_enable &= ~(2 << (2 * nr));
+ break; /* Normal auto mode */
+ default:
+ count = -EINVAL;
+ goto leave;
+ }
+ }
+ f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
+leave:
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_auto_point_pwm(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ int result;
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int pwm = to_sensor_dev_attr_2(devattr)->index;
+ int point = to_sensor_dev_attr_2(devattr)->nr;
+
+ mutex_lock(&data->update_lock);
+ if (data->pwm_enable & (1 << (2 * pwm))) {
+ /* PWM mode */
+ result = data->pwm_auto_point_pwm[pwm][point];
+ } else {
+ /* RPM mode */
+ result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%d\n", result);
+}
+
+static ssize_t store_pwm_auto_point_pwm(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int pwm = to_sensor_dev_attr_2(devattr)->index;
+ int point = to_sensor_dev_attr_2(devattr)->nr;
+ long val = simple_strtol(buf, NULL, 10);
+ val = SENSORS_LIMIT(val, 0, 255);
+
+ mutex_lock(&data->update_lock);
+ data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
+ if (data->pwm_enable & (1 << (2 * pwm))) {
+ /* PWM mode */
+ } else {
+ /* RPM mode */
+ if (val < 29) /* Prevent negative numbers */
+ val = 255;
+ else
+ val = (255 - val) * 32 / val;
+ }
+ f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
+ data->pwm_auto_point_pwm[pwm][point] = val;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ int result = 0;
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ int point = to_sensor_dev_attr_2(devattr)->nr;
+
+ mutex_lock(&data->update_lock);
+ if (nr & 1)
+ result = data->pwm_auto_point_hyst[nr / 2] >> 4;
+ else
+ result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
+ result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%d\n", result);
+}
+
+static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ int point = to_sensor_dev_attr_2(devattr)->nr;
+ long val = simple_strtol(buf, NULL, 10) / 1000;
+ u8 reg;
+
+ mutex_lock(&data->update_lock);
+ data->pwm_auto_point_temp[nr][point] =
+ f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
+ val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
+ data->pwm_auto_point_temp[nr][point]);
+ val = data->pwm_auto_point_temp[nr][point] - val;
+
+ reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
+ if (nr & 1)
+ reg = (reg & 0x0f) | (val << 4);
+ else
+ reg = (reg & 0xf0) | val;
+
+ f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
+ data->pwm_auto_point_hyst[nr / 2] = reg;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_interpolate(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int result;
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+
+ result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
+
+ return sprintf(buf, "%d\n", result);
+}
+
+static ssize_t store_pwm_interpolate(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->pwm_auto_point_mapping[nr] =
+ f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
+ if (val)
+ val = data->pwm_auto_point_mapping[nr] | (1 << 4);
+ else
+ val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
+ f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
+ data->pwm_auto_point_mapping[nr] = val;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_auto_point_channel(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ int result;
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ int temp_start = (data->type == f8000) ? 0 : 1;
+
+ result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - temp_start);
+
+ return sprintf(buf, "%d\n", result);
+}
+
+static ssize_t store_pwm_auto_point_channel(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int nr = to_sensor_dev_attr_2(devattr)->index;
+ int temp_start = (data->type == f8000) ? 0 : 1;
+ long val = simple_strtol(buf, NULL, 10);
+
+ switch (val) {
+ case 1:
+ val = 0;
+ break;
+ case 2:
+ val = 1;
+ break;
+ case 4:
+ val = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+ val += temp_start;
+ mutex_lock(&data->update_lock);
+ data->pwm_auto_point_mapping[nr] =
+ f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
+ val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
+ f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
+ data->pwm_auto_point_mapping[nr] = val;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_auto_point_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ int result;
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int pwm = to_sensor_dev_attr_2(devattr)->index;
+ int point = to_sensor_dev_attr_2(devattr)->nr;
+
+ result = data->pwm_auto_point_temp[pwm][point];
+ return sprintf(buf, "%d\n", 1000 * result);
+}
+
+static ssize_t store_pwm_auto_point_temp(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int pwm = to_sensor_dev_attr_2(devattr)->index;
+ int point = to_sensor_dev_attr_2(devattr)->nr;
+ long val = simple_strtol(buf, NULL, 10) / 1000;
+ val = SENSORS_LIMIT(val, 0, 255);
+
+ mutex_lock(&data->update_lock);
+ f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
+ data->pwm_auto_point_temp[pwm][point] = val;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
char *buf)
{
- return sprintf(buf, DRVNAME "\n");
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", f71882fg_names[data->type]);
}
+static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
+ struct sensor_device_attribute_2 *attr, int count)
+{
+ int err, i;
+
+ for (i = 0; i < count; i++) {
+ err = device_create_file(&pdev->dev, &attr[i].dev_attr);
+ if (err)
+ return err;
+ }
+ return 0;
+}
-static int __devinit f71882fg_probe(struct platform_device * pdev)
+static int __devinit f71882fg_probe(struct platform_device *pdev)
{
struct f71882fg_data *data;
- int err, i;
+ struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
+ int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
u8 start_reg;
- if (!(data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL)))
+ data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
+ if (!data)
return -ENOMEM;
data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+ data->type = sio_data->type;
mutex_init(&data->update_lock);
platform_set_drvdata(pdev, data);
- /* Register sysfs interface files */
- for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++) {
- err = device_create_file(&pdev->dev, &f71882fg_dev_attr[i]);
- if (err)
- goto exit_unregister_sysfs;
+ start_reg = f71882fg_read8(data, F71882FG_REG_START);
+ if (start_reg & 0x04) {
+ dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
+ err = -ENODEV;
+ goto exit_free;
+ }
+ if (!(start_reg & 0x03)) {
+ dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
+ err = -ENODEV;
+ goto exit_free;
}
- start_reg = f71882fg_read8(data, F71882FG_REG_START);
+ data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
+ /* If it is a 71862 and the fan / pwm part is enabled sanity check
+ the pwm settings */
+ if (data->type == f71862fg && (start_reg & 0x02)) {
+ if ((data->pwm_enable & 0x15) != 0x15) {
+ dev_err(&pdev->dev,
+ "Invalid (reserved) pwm settings: 0x%02x\n",
+ (unsigned int)data->pwm_enable);
+ err = -ENODEV;
+ goto exit_free;
+ }
+ }
+
+ /* Register sysfs interface files */
+ err = device_create_file(&pdev->dev, &dev_attr_name);
+ if (err)
+ goto exit_unregister_sysfs;
+
if (start_reg & 0x01) {
- for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++) {
- err = device_create_file(&pdev->dev,
- &f71882fg_in_temp_attr[i].dev_attr);
+ switch (data->type) {
+ case f71882fg:
+ err = f71882fg_create_sysfs_files(pdev,
+ f71882fg_in_temp_attr,
+ ARRAY_SIZE(f71882fg_in_temp_attr));
if (err)
goto exit_unregister_sysfs;
+ /* fall through! */
+ case f71862fg:
+ err = f71882fg_create_sysfs_files(pdev,
+ f718x2fg_in_temp_attr,
+ ARRAY_SIZE(f718x2fg_in_temp_attr));
+ break;
+ case f8000:
+ err = f71882fg_create_sysfs_files(pdev,
+ f8000_in_temp_attr,
+ ARRAY_SIZE(f8000_in_temp_attr));
+ break;
}
+ if (err)
+ goto exit_unregister_sysfs;
}
if (start_reg & 0x02) {
- for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++) {
- err = device_create_file(&pdev->dev,
- &f71882fg_fan_attr[i].dev_attr);
- if (err)
- goto exit_unregister_sysfs;
+ err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr,
+ ARRAY_SIZE(fxxxx_fan_attr));
+ if (err)
+ goto exit_unregister_sysfs;
+
+ switch (data->type) {
+ case f71862fg:
+ err = f71882fg_create_sysfs_files(pdev,
+ f71862fg_fan_attr,
+ ARRAY_SIZE(f71862fg_fan_attr));
+ break;
+ case f71882fg:
+ err = f71882fg_create_sysfs_files(pdev,
+ f71882fg_fan_attr,
+ ARRAY_SIZE(f71882fg_fan_attr));
+ break;
+ case f8000:
+ err = f71882fg_create_sysfs_files(pdev,
+ f8000_fan_attr,
+ ARRAY_SIZE(f8000_fan_attr));
+ break;
}
+ if (err)
+ goto exit_unregister_sysfs;
+
+ for (i = 0; i < nr_fans; i++)
+ dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
+ (data->pwm_enable & (1 << 2 * i)) ?
+ "duty-cycle" : "RPM");
}
data->hwmon_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
+ data->hwmon_dev = NULL;
goto exit_unregister_sysfs;
}
return 0;
exit_unregister_sysfs:
- for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++)
- device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]);
-
- for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
- device_remove_file(&pdev->dev,
- &f71882fg_in_temp_attr[i].dev_attr);
-
- for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
- device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
-
+ f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
+ return err; /* f71882fg_remove() also frees our data */
+exit_free:
kfree(data);
-
return err;
}
-static int __devexit f71882fg_remove(struct platform_device *pdev)
+static int f71882fg_remove(struct platform_device *pdev)
{
int i;
struct f71882fg_data *data = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
- hwmon_device_unregister(data->hwmon_dev);
+ if (data->hwmon_dev)
+ hwmon_device_unregister(data->hwmon_dev);
+
+ /* Note we are not looping over all attr arrays we have as the ones
+ below are supersets of the ones skipped. */
+ device_remove_file(&pdev->dev, &dev_attr_name);
- for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++)
- device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]);
+ for (i = 0; i < ARRAY_SIZE(f718x2fg_in_temp_attr); i++)
+ device_remove_file(&pdev->dev,
+ &f718x2fg_in_temp_attr[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
device_remove_file(&pdev->dev,
&f71882fg_in_temp_attr[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(fxxxx_fan_attr); i++)
+ device_remove_file(&pdev->dev, &fxxxx_fan_attr[i].dev_attr);
+
for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(f8000_fan_attr); i++)
+ device_remove_file(&pdev->dev, &f8000_fan_attr[i].dev_attr);
+
kfree(data);
return 0;
}
-static int __init f71882fg_find(int sioaddr, unsigned short *address)
+static int __init f71882fg_find(int sioaddr, unsigned short *address,
+ struct f71882fg_sio_data *sio_data)
{
int err = -ENODEV;
u16 devid;
- u8 start_reg;
- struct f71882fg_data data;
superio_enter(sioaddr);
@@ -842,7 +1877,17 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address)
}
devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
- if (devid != SIO_F71882_ID) {
+ switch (devid) {
+ case SIO_F71862_ID:
+ sio_data->type = f71862fg;
+ break;
+ case SIO_F71882_ID:
+ sio_data->type = f71882fg;
+ break;
+ case SIO_F8000_ID:
+ sio_data->type = f8000;
+ break;
+ default:
printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
goto exit;
}
@@ -861,24 +1906,17 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address)
}
*address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
- data.addr = *address;
- start_reg = f71882fg_read8(&data, F71882FG_REG_START);
- if (!(start_reg & 0x03)) {
- printk(KERN_WARNING DRVNAME
- ": Hardware monitoring not activated\n");
- goto exit;
- }
-
err = 0;
- printk(KERN_INFO DRVNAME ": Found F71882FG chip at %#x, revision %d\n",
- (unsigned int)*address,
+ printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
+ f71882fg_names[sio_data->type], (unsigned int)*address,
(int)superio_inb(sioaddr, SIO_REG_DEVREV));
exit:
superio_exit(sioaddr);
return err;
}
-static int __init f71882fg_device_add(unsigned short address)
+static int __init f71882fg_device_add(unsigned short address,
+ const struct f71882fg_sio_data *sio_data)
{
struct resource res = {
.start = address,
@@ -892,12 +1930,23 @@ static int __init f71882fg_device_add(unsigned short address)
return -ENOMEM;
res.name = f71882fg_pdev->name;
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ return err;
+
err = platform_device_add_resources(f71882fg_pdev, &res, 1);
if (err) {
printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
goto exit_device_put;
}
+ err = platform_device_add_data(f71882fg_pdev, sio_data,
+ sizeof(struct f71882fg_sio_data));
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+ goto exit_device_put;
+ }
+
err = platform_device_add(f71882fg_pdev);
if (err) {
printk(KERN_ERR DRVNAME ": Device addition failed\n");
@@ -916,14 +1965,20 @@ static int __init f71882fg_init(void)
{
int err = -ENODEV;
unsigned short address;
+ struct f71882fg_sio_data sio_data;
+
+ memset(&sio_data, 0, sizeof(sio_data));
- if (f71882fg_find(0x2e, &address) && f71882fg_find(0x4e, &address))
+ if (f71882fg_find(0x2e, &address, &sio_data) &&
+ f71882fg_find(0x4e, &address, &sio_data))
goto exit;
- if ((err = platform_driver_register(&f71882fg_driver)))
+ err = platform_driver_register(&f71882fg_driver);
+ if (err)
goto exit;
- if ((err = f71882fg_device_add(address)))
+ err = f71882fg_device_add(address, &sio_data);
+ if (err)
goto exit_driver;
return 0;
@@ -941,7 +1996,7 @@ static void __exit f71882fg_exit(void)
}
MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
-MODULE_AUTHOR("Hans Edgington (hans@edgington.nl)");
+MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
MODULE_LICENSE("GPL");
module_init(f71882fg_init);
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index 967170368933..d07f4ef75092 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -1,6 +1,6 @@
/* fschmd.c
*
- * Copyright (C) 2007 Hans de Goede <j.w.r.degoede@hhs.nl>
+ * Copyright (C) 2007,2008 Hans de Goede <hdegoede@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
@@ -42,11 +42,20 @@
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/dmi.h>
+#include <linux/fs.h>
+#include <linux/watchdog.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/kref.h>
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
/* Insmod parameters */
+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) ")");
I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
/*
@@ -63,19 +72,26 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
#define FSCHMD_REG_EVENT_STATE 0x04
#define FSCHMD_REG_CONTROL 0x05
-#define FSCHMD_CONTROL_ALERT_LED_MASK 0x01
+#define FSCHMD_CONTROL_ALERT_LED 0x01
-/* watchdog (support to be implemented) */
+/* watchdog */
#define FSCHMD_REG_WDOG_PRESET 0x28
#define FSCHMD_REG_WDOG_STATE 0x23
#define FSCHMD_REG_WDOG_CONTROL 0x21
+#define FSCHMD_WDOG_CONTROL_TRIGGER 0x10
+#define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */
+#define FSCHMD_WDOG_CONTROL_STOP 0x20
+#define FSCHMD_WDOG_CONTROL_RESOLUTION 0x40
+
+#define FSCHMD_WDOG_STATE_CARDRESET 0x02
+
/* voltages, weird order is to keep the same order as the old drivers */
static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 };
/* minimum pwm at which the fan is driven (pwm can by increased depending on
the temp. Notice that for the scy some fans share there minimum speed.
- Also notice that with the scy the sensor order is different then with the
+ Also notice that with the scy the sensor order is different than with the
other chips, this order was in the 2.4 driver and kept for consistency. */
static const u8 FSCHMD_REG_FAN_MIN[5][6] = {
{ 0x55, 0x65 }, /* pos */
@@ -115,8 +131,8 @@ static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = {
static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 };
/* Fan status register bitmasks */
-#define FSCHMD_FAN_ALARM_MASK 0x04 /* called fault by FSC! */
-#define FSCHMD_FAN_NOT_PRESENT_MASK 0x08 /* not documented */
+#define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */
+#define FSCHMD_FAN_NOT_PRESENT 0x08 /* not documented */
/* actual temperature registers */
@@ -158,14 +174,11 @@ static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */
static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 };
/* temp status register bitmasks */
-#define FSCHMD_TEMP_WORKING_MASK 0x01
-#define FSCHMD_TEMP_ALERT_MASK 0x02
+#define FSCHMD_TEMP_WORKING 0x01
+#define FSCHMD_TEMP_ALERT 0x02
/* there only really is an alarm if the sensor is working and alert == 1 */
#define FSCHMD_TEMP_ALARM_MASK \
- (FSCHMD_TEMP_WORKING_MASK | FSCHMD_TEMP_ALERT_MASK)
-
-/* our driver name */
-#define FSCHMD_NAME "fschmd"
+ (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT)
/*
* Functions declarations
@@ -195,7 +208,7 @@ MODULE_DEVICE_TABLE(i2c, fschmd_id);
static struct i2c_driver fschmd_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
- .name = FSCHMD_NAME,
+ .name = "fschmd",
},
.probe = fschmd_probe,
.remove = fschmd_remove,
@@ -209,14 +222,26 @@ static struct i2c_driver fschmd_driver = {
*/
struct fschmd_data {
+ struct i2c_client *client;
struct device *hwmon_dev;
struct mutex update_lock;
+ struct mutex watchdog_lock;
+ struct list_head list; /* member of the watchdog_data_list */
+ struct kref kref;
+ struct miscdevice watchdog_miscdev;
int kind;
+ unsigned long watchdog_is_open;
+ char watchdog_expect_close;
+ char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
/* register values */
+ u8 revision; /* chip revision */
u8 global_control; /* global control register */
+ u8 watchdog_control; /* watchdog control register */
+ u8 watchdog_state; /* watchdog status register */
+ u8 watchdog_preset; /* watchdog counter preset on trigger val */
u8 volt[3]; /* 12, 5, battery voltage */
u8 temp_act[5]; /* temperature */
u8 temp_status[5]; /* status of sensor */
@@ -228,11 +253,28 @@ struct fschmd_data {
};
/* Global variables to hold information read from special DMI tables, which are
- available on FSC machines with an fscher or later chip. */
+ available on FSC machines with an fscher or later chip. There is no need to
+ protect these with a lock as they are only modified from our attach function
+ which always gets called with the i2c-core lock held and never accessed
+ before the attach function is done with them. */
static int dmi_mult[3] = { 490, 200, 100 };
static int dmi_offset[3] = { 0, 0, 0 };
static int dmi_vref = -1;
+/* Somewhat ugly :( global data pointer list with all fschmd devices, so that
+ we can find our device data as when using misc_register there is no other
+ method to get to ones device data from the open fop. */
+static LIST_HEAD(watchdog_data_list);
+/* Note this lock not only protect list access, but also data.kref access */
+static DEFINE_MUTEX(watchdog_data_mutex);
+
+/* Release our data struct when we're detached from the i2c client *and* all
+ references to our watchdog device are released */
+static void fschmd_release_resources(struct kref *ref)
+{
+ struct fschmd_data *data = container_of(ref, struct fschmd_data, kref);
+ kfree(data);
+}
/*
* Sysfs attr show / store functions
@@ -300,7 +342,7 @@ static ssize_t show_temp_fault(struct device *dev,
struct fschmd_data *data = fschmd_update_device(dev);
/* bit 0 set means sensor working ok, so no fault! */
- if (data->temp_status[index] & FSCHMD_TEMP_WORKING_MASK)
+ if (data->temp_status[index] & FSCHMD_TEMP_WORKING)
return sprintf(buf, "0\n");
else
return sprintf(buf, "1\n");
@@ -385,7 +427,7 @@ static ssize_t show_fan_alarm(struct device *dev,
int index = to_sensor_dev_attr(devattr)->index;
struct fschmd_data *data = fschmd_update_device(dev);
- if (data->fan_status[index] & FSCHMD_FAN_ALARM_MASK)
+ if (data->fan_status[index] & FSCHMD_FAN_ALARM)
return sprintf(buf, "1\n");
else
return sprintf(buf, "0\n");
@@ -397,7 +439,7 @@ static ssize_t show_fan_fault(struct device *dev,
int index = to_sensor_dev_attr(devattr)->index;
struct fschmd_data *data = fschmd_update_device(dev);
- if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT_MASK)
+ if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT)
return sprintf(buf, "1\n");
else
return sprintf(buf, "0\n");
@@ -449,7 +491,7 @@ static ssize_t show_alert_led(struct device *dev,
{
struct fschmd_data *data = fschmd_update_device(dev);
- if (data->global_control & FSCHMD_CONTROL_ALERT_LED_MASK)
+ if (data->global_control & FSCHMD_CONTROL_ALERT_LED)
return sprintf(buf, "1\n");
else
return sprintf(buf, "0\n");
@@ -467,9 +509,9 @@ static ssize_t store_alert_led(struct device *dev,
reg = i2c_smbus_read_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL);
if (v)
- reg |= FSCHMD_CONTROL_ALERT_LED_MASK;
+ reg |= FSCHMD_CONTROL_ALERT_LED;
else
- reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK;
+ reg &= ~FSCHMD_CONTROL_ALERT_LED;
i2c_smbus_write_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL, reg);
@@ -551,7 +593,265 @@ static struct sensor_device_attribute fschmd_fan_attr[] = {
/*
- * Real code
+ * Watchdog routines
+ */
+
+static int watchdog_set_timeout(struct fschmd_data *data, int timeout)
+{
+ int ret, resolution;
+ int kind = data->kind + 1; /* 0-x array index -> 1-x module param */
+
+ /* 2 second or 60 second resolution? */
+ if (timeout <= 510 || kind == fscpos || kind == fscscy)
+ resolution = 2;
+ else
+ resolution = 60;
+
+ if (timeout < resolution || timeout > (resolution * 255))
+ return -EINVAL;
+
+ mutex_lock(&data->watchdog_lock);
+ if (!data->client) {
+ ret = -ENODEV;
+ goto leave;
+ }
+
+ if (resolution == 2)
+ data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_RESOLUTION;
+ else
+ data->watchdog_control |= FSCHMD_WDOG_CONTROL_RESOLUTION;
+
+ data->watchdog_preset = DIV_ROUND_UP(timeout, resolution);
+
+ /* Write new timeout value */
+ i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_PRESET,
+ data->watchdog_preset);
+ /* Write new control register, do not trigger! */
+ i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
+ data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER);
+
+ ret = data->watchdog_preset * resolution;
+
+leave:
+ mutex_unlock(&data->watchdog_lock);
+ return ret;
+}
+
+static int watchdog_get_timeout(struct fschmd_data *data)
+{
+ int timeout;
+
+ mutex_lock(&data->watchdog_lock);
+ if (data->watchdog_control & FSCHMD_WDOG_CONTROL_RESOLUTION)
+ timeout = data->watchdog_preset * 60;
+ else
+ timeout = data->watchdog_preset * 2;
+ mutex_unlock(&data->watchdog_lock);
+
+ return timeout;
+}
+
+static int watchdog_trigger(struct fschmd_data *data)
+{
+ int ret = 0;
+
+ mutex_lock(&data->watchdog_lock);
+ if (!data->client) {
+ ret = -ENODEV;
+ goto leave;
+ }
+
+ data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER;
+ i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
+ data->watchdog_control);
+leave:
+ mutex_unlock(&data->watchdog_lock);
+ return ret;
+}
+
+static int watchdog_stop(struct fschmd_data *data)
+{
+ int ret = 0;
+
+ mutex_lock(&data->watchdog_lock);
+ if (!data->client) {
+ ret = -ENODEV;
+ goto leave;
+ }
+
+ data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED;
+ /* Don't store the stop flag in our watchdog control register copy, as
+ its a write only bit (read always returns 0) */
+ i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
+ data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP);
+leave:
+ mutex_unlock(&data->watchdog_lock);
+ return ret;
+}
+
+static int watchdog_open(struct inode *inode, struct file *filp)
+{
+ struct fschmd_data *pos, *data = NULL;
+
+ /* We get called from drivers/char/misc.c with misc_mtx hold, and we
+ call misc_register() from fschmd_probe() with watchdog_data_mutex
+ hold, as misc_register() takes the misc_mtx lock, this is a possible
+ deadlock, so we use mutex_trylock here. */
+ if (!mutex_trylock(&watchdog_data_mutex))
+ return -ERESTARTSYS;
+ list_for_each_entry(pos, &watchdog_data_list, list) {
+ if (pos->watchdog_miscdev.minor == iminor(inode)) {
+ data = pos;
+ break;
+ }
+ }
+ /* Note we can never not have found data, so we don't check for this */
+ kref_get(&data->kref);
+ mutex_unlock(&watchdog_data_mutex);
+
+ if (test_and_set_bit(0, &data->watchdog_is_open))
+ return -EBUSY;
+
+ /* Start the watchdog */
+ watchdog_trigger(data);
+ filp->private_data = data;
+
+ return nonseekable_open(inode, filp);
+}
+
+static int watchdog_release(struct inode *inode, struct file *filp)
+{
+ struct fschmd_data *data = filp->private_data;
+
+ if (data->watchdog_expect_close) {
+ watchdog_stop(data);
+ data->watchdog_expect_close = 0;
+ } else {
+ watchdog_trigger(data);
+ dev_crit(&data->client->dev,
+ "unexpected close, not stopping watchdog!\n");
+ }
+
+ clear_bit(0, &data->watchdog_is_open);
+
+ mutex_lock(&watchdog_data_mutex);
+ kref_put(&data->kref, fschmd_release_resources);
+ mutex_unlock(&watchdog_data_mutex);
+
+ return 0;
+}
+
+static ssize_t watchdog_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *offset)
+{
+ size_t ret;
+ struct fschmd_data *data = filp->private_data;
+
+ if (count) {
+ if (!nowayout) {
+ size_t i;
+
+ /* Clear it in case it was set with a previous write */
+ data->watchdog_expect_close = 0;
+
+ for (i = 0; i != count; i++) {
+ char c;
+ if (get_user(c, buf + i))
+ return -EFAULT;
+ if (c == 'V')
+ data->watchdog_expect_close = 1;
+ }
+ }
+ ret = watchdog_trigger(data);
+ if (ret < 0)
+ return ret;
+ }
+ return count;
+}
+
+static int watchdog_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ static struct watchdog_info ident = {
+ .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
+ WDIOF_CARDRESET,
+ .identity = "FSC watchdog"
+ };
+ int i, ret = 0;
+ struct fschmd_data *data = filp->private_data;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ident.firmware_version = data->revision;
+ if (!nowayout)
+ ident.options |= WDIOF_MAGICCLOSE;
+ if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
+ ret = -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ ret = put_user(0, (int __user *)arg);
+ break;
+
+ case WDIOC_GETBOOTSTATUS:
+ if (data->watchdog_state & FSCHMD_WDOG_STATE_CARDRESET)
+ ret = put_user(WDIOF_CARDRESET, (int __user *)arg);
+ else
+ ret = put_user(0, (int __user *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ ret = watchdog_trigger(data);
+ break;
+
+ case WDIOC_GETTIMEOUT:
+ i = watchdog_get_timeout(data);
+ ret = put_user(i, (int __user *)arg);
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(i, (int __user *)arg)) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = watchdog_set_timeout(data, i);
+ if (ret > 0)
+ ret = put_user(ret, (int __user *)arg);
+ break;
+
+ case WDIOC_SETOPTIONS:
+ if (get_user(i, (int __user *)arg)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ if (i & WDIOS_DISABLECARD)
+ ret = watchdog_stop(data);
+ else if (i & WDIOS_ENABLECARD)
+ ret = watchdog_trigger(data);
+ else
+ ret = -EINVAL;
+
+ break;
+ default:
+ ret = -ENOTTY;
+ }
+
+ return ret;
+}
+
+static struct file_operations watchdog_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .open = watchdog_open,
+ .release = watchdog_release,
+ .write = watchdog_write,
+ .ioctl = watchdog_ioctl,
+};
+
+
+/*
+ * Detect, register, unregister and update device functions
*/
/* DMI decode routine to read voltage scaling factors from special DMI tables,
@@ -661,9 +961,9 @@ static int fschmd_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct fschmd_data *data;
- u8 revision;
const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
"Heracles", "Heimdall" };
+ const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
int i, err;
enum chips kind = id->driver_data;
@@ -673,6 +973,13 @@ static int fschmd_probe(struct i2c_client *client,
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
+ mutex_init(&data->watchdog_lock);
+ INIT_LIST_HEAD(&data->list);
+ kref_init(&data->kref);
+ /* Store client pointer in our data struct for watchdog usage
+ (where the client is found through a data ptr instead of the
+ otherway around) */
+ data->client = client;
if (kind == fscpos) {
/* The Poseidon has hardwired temp limits, fill these
@@ -683,16 +990,27 @@ static int fschmd_probe(struct i2c_client *client,
}
/* Read the special DMI table for fscher and newer chips */
- if (kind == fscher || kind >= fschrc) {
+ if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) {
dmi_walk(fschmd_dmi_decode);
if (dmi_vref == -1) {
- printk(KERN_WARNING FSCHMD_NAME
- ": Couldn't get voltage scaling factors from "
+ dev_warn(&client->dev,
+ "Couldn't get voltage scaling factors from "
"BIOS DMI table, using builtin defaults\n");
dmi_vref = 33;
}
}
+ /* Read in some never changing registers */
+ data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
+ data->global_control = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_CONTROL);
+ data->watchdog_control = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_WDOG_CONTROL);
+ data->watchdog_state = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_WDOG_STATE);
+ data->watchdog_preset = i2c_smbus_read_byte_data(client,
+ FSCHMD_REG_WDOG_PRESET);
+
/* i2c kind goes from 1-5, we want from 0-4 to address arrays */
data->kind = kind - 1;
@@ -735,9 +1053,43 @@ static int fschmd_probe(struct i2c_client *client,
goto exit_detach;
}
- revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
- printk(KERN_INFO FSCHMD_NAME ": Detected FSC %s chip, revision: %d\n",
- names[data->kind], (int) revision);
+ /* We take the data_mutex lock early so that watchdog_open() cannot
+ run when misc_register() has completed, but we've not yet added
+ our data to the watchdog_data_list (and set the default timeout) */
+ mutex_lock(&watchdog_data_mutex);
+ for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) {
+ /* Register our watchdog part */
+ snprintf(data->watchdog_name, sizeof(data->watchdog_name),
+ "watchdog%c", (i == 0) ? '\0' : ('0' + i));
+ data->watchdog_miscdev.name = data->watchdog_name;
+ data->watchdog_miscdev.fops = &watchdog_fops;
+ data->watchdog_miscdev.minor = watchdog_minors[i];
+ err = misc_register(&data->watchdog_miscdev);
+ if (err == -EBUSY)
+ continue;
+ if (err) {
+ data->watchdog_miscdev.minor = 0;
+ dev_err(&client->dev,
+ "Registering watchdog chardev: %d\n", err);
+ break;
+ }
+
+ list_add(&data->list, &watchdog_data_list);
+ watchdog_set_timeout(data, 60);
+ dev_info(&client->dev,
+ "Registered watchdog chardev major 10, minor: %d\n",
+ watchdog_minors[i]);
+ break;
+ }
+ if (i == ARRAY_SIZE(watchdog_minors)) {
+ data->watchdog_miscdev.minor = 0;
+ dev_warn(&client->dev, "Couldn't register watchdog chardev "
+ "(due to no free minor)\n");
+ }
+ mutex_unlock(&watchdog_data_mutex);
+
+ dev_info(&client->dev, "Detected FSC %s chip, revision: %d\n",
+ names[data->kind], (int) data->revision);
return 0;
@@ -751,6 +1103,24 @@ static int fschmd_remove(struct i2c_client *client)
struct fschmd_data *data = i2c_get_clientdata(client);
int i;
+ /* Unregister the watchdog (if registered) */
+ if (data->watchdog_miscdev.minor) {
+ misc_deregister(&data->watchdog_miscdev);
+ if (data->watchdog_is_open) {
+ dev_warn(&client->dev,
+ "i2c client detached with watchdog open! "
+ "Stopping watchdog.\n");
+ watchdog_stop(data);
+ }
+ mutex_lock(&watchdog_data_mutex);
+ list_del(&data->list);
+ mutex_unlock(&watchdog_data_mutex);
+ /* Tell the watchdog code the client is gone */
+ mutex_lock(&data->watchdog_lock);
+ data->client = NULL;
+ mutex_unlock(&data->watchdog_lock);
+ }
+
/* Check if registered in case we're called from fschmd_detect
to cleanup after an error */
if (data->hwmon_dev)
@@ -765,7 +1135,10 @@ static int fschmd_remove(struct i2c_client *client)
device_remove_file(&client->dev,
&fschmd_fan_attr[i].dev_attr);
- kfree(data);
+ mutex_lock(&watchdog_data_mutex);
+ kref_put(&data->kref, fschmd_release_resources);
+ mutex_unlock(&watchdog_data_mutex);
+
return 0;
}
@@ -798,7 +1171,7 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
data->temp_act[i] < data->temp_max[i])
i2c_smbus_write_byte_data(client,
FSCHMD_REG_TEMP_STATE[data->kind][i],
- FSCHMD_TEMP_ALERT_MASK);
+ FSCHMD_TEMP_ALERT);
}
for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
@@ -816,28 +1189,17 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
FSCHMD_REG_FAN_MIN[data->kind][i]);
/* reset fan status if speed is back to > 0 */
- if ((data->fan_status[i] & FSCHMD_FAN_ALARM_MASK) &&
+ if ((data->fan_status[i] & FSCHMD_FAN_ALARM) &&
data->fan_act[i])
i2c_smbus_write_byte_data(client,
FSCHMD_REG_FAN_STATE[data->kind][i],
- FSCHMD_FAN_ALARM_MASK);
+ FSCHMD_FAN_ALARM);
}
for (i = 0; i < 3; i++)
data->volt[i] = i2c_smbus_read_byte_data(client,
FSCHMD_REG_VOLT[i]);
- data->global_control = i2c_smbus_read_byte_data(client,
- FSCHMD_REG_CONTROL);
-
- /* To be implemented in the future
- data->watchdog[0] = i2c_smbus_read_byte_data(client,
- FSCHMD_REG_WDOG_PRESET);
- data->watchdog[1] = i2c_smbus_read_byte_data(client,
- FSCHMD_REG_WDOG_STATE);
- data->watchdog[2] = i2c_smbus_read_byte_data(client,
- FSCHMD_REG_WDOG_CONTROL); */
-
data->last_updated = jiffies;
data->valid = 1;
}
@@ -857,7 +1219,7 @@ static void __exit fschmd_exit(void)
i2c_del_driver(&fschmd_driver);
}
-MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and "
"Heimdall driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c
new file mode 100644
index 000000000000..03705240000f
--- /dev/null
+++ b/drivers/hwmon/hp_accel.c
@@ -0,0 +1,334 @@
+/*
+ * hp_accel.c - Interface between LIS3LV02DL driver and HP ACPI BIOS
+ *
+ * Copyright (C) 2007-2008 Yan Burman
+ * Copyright (C) 2008 Eric Piel
+ * Copyright (C) 2008-2009 Pavel Machek
+ *
+ * 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/init.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/kthread.h>
+#include <linux/semaphore.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/poll.h>
+#include <linux/freezer.h>
+#include <linux/version.h>
+#include <linux/uaccess.h>
+#include <linux/leds.h>
+#include <acpi/acpi_drivers.h>
+#include <asm/atomic.h>
+#include "lis3lv02d.h"
+
+#define DRIVER_NAME "lis3lv02d"
+#define ACPI_MDPS_CLASS "accelerometer"
+
+/* Delayed LEDs infrastructure ------------------------------------ */
+
+/* Special LED class that can defer work */
+struct delayed_led_classdev {
+ struct led_classdev led_classdev;
+ struct work_struct work;
+ enum led_brightness new_brightness;
+
+ unsigned int led; /* For driver */
+ void (*set_brightness)(struct delayed_led_classdev *data, enum led_brightness value);
+};
+
+static inline void delayed_set_status_worker(struct work_struct *work)
+{
+ struct delayed_led_classdev *data =
+ container_of(work, struct delayed_led_classdev, work);
+
+ data->set_brightness(data, data->new_brightness);
+}
+
+static inline void delayed_sysfs_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct delayed_led_classdev *data = container_of(led_cdev,
+ struct delayed_led_classdev, led_classdev);
+ data->new_brightness = brightness;
+ schedule_work(&data->work);
+}
+
+/* HP-specific accelerometer driver ------------------------------------ */
+
+/* For automatic insertion of the module */
+static struct acpi_device_id lis3lv02d_device_ids[] = {
+ {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
+
+
+/**
+ * lis3lv02d_acpi_init - ACPI _INI method: initialize the device.
+ * @handle: the handle of the device
+ *
+ * Returns AE_OK on success.
+ */
+acpi_status lis3lv02d_acpi_init(acpi_handle handle)
+{
+ return acpi_evaluate_object(handle, METHOD_NAME__INI, NULL, NULL);
+}
+
+/**
+ * lis3lv02d_acpi_read - ACPI ALRD method: read a register
+ * @handle: the handle of the device
+ * @reg: the register to read
+ * @ret: result of the operation
+ *
+ * Returns AE_OK on success.
+ */
+acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret)
+{
+ union acpi_object arg0 = { ACPI_TYPE_INTEGER };
+ struct acpi_object_list args = { 1, &arg0 };
+ unsigned long long lret;
+ acpi_status status;
+
+ arg0.integer.value = reg;
+
+ status = acpi_evaluate_integer(handle, "ALRD", &args, &lret);
+ *ret = lret;
+ return status;
+}
+
+/**
+ * lis3lv02d_acpi_write - ACPI ALWR method: write to a register
+ * @handle: the handle of the device
+ * @reg: the register to write to
+ * @val: the value to write
+ *
+ * Returns AE_OK on success.
+ */
+acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val)
+{
+ unsigned long long ret; /* Not used when writting */
+ union acpi_object in_obj[2];
+ struct acpi_object_list args = { 2, in_obj };
+
+ in_obj[0].type = ACPI_TYPE_INTEGER;
+ in_obj[0].integer.value = reg;
+ in_obj[1].type = ACPI_TYPE_INTEGER;
+ in_obj[1].integer.value = val;
+
+ return acpi_evaluate_integer(handle, "ALWR", &args, &ret);
+}
+
+static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
+{
+ adev.ac = *((struct axis_conversion *)dmi->driver_data);
+ printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident);
+
+ return 1;
+}
+
+/* Represents, for each axis seen by userspace, the corresponding hw axis (+1).
+ * If the value is negative, the opposite of the hw value is used. */
+static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3};
+static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3};
+static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3};
+static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3};
+static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3};
+static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3};
+
+#define AXIS_DMI_MATCH(_ident, _name, _axis) { \
+ .ident = _ident, \
+ .callback = lis3lv02d_dmi_matched, \
+ .matches = { \
+ DMI_MATCH(DMI_PRODUCT_NAME, _name) \
+ }, \
+ .driver_data = &lis3lv02d_axis_##_axis \
+}
+static struct dmi_system_id lis3lv02d_dmi_ids[] = {
+ /* product names are truncated to match all kinds of a same model */
+ AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted),
+ AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted),
+ AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted),
+ AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted),
+ AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted),
+ AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted),
+ AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left),
+ { NULL, }
+/* Laptop models without axis info (yet):
+ * "NC651xx" "HP Compaq 651"
+ * "NC671xx" "HP Compaq 671"
+ * "NC6910" "HP Compaq 6910"
+ * HP Compaq 8710x Notebook PC / Mobile Workstation
+ * "NC2400" "HP Compaq nc2400"
+ * "NX74x0" "HP Compaq nx74"
+ * "NX6325" "HP Compaq nx6325"
+ * "NC4400" "HP Compaq nc4400"
+ */
+};
+
+static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value)
+{
+ acpi_handle handle = adev.device->handle;
+ unsigned long long ret; /* Not used when writing */
+ union acpi_object in_obj[1];
+ struct acpi_object_list args = { 1, in_obj };
+
+ in_obj[0].type = ACPI_TYPE_INTEGER;
+ in_obj[0].integer.value = !!value;
+
+ acpi_evaluate_integer(handle, "ALED", &args, &ret);
+}
+
+static struct delayed_led_classdev hpled_led = {
+ .led_classdev = {
+ .name = "hp::hddprotect",
+ .default_trigger = "none",
+ .brightness_set = delayed_sysfs_set,
+ .flags = LED_CORE_SUSPENDRESUME,
+ },
+ .set_brightness = hpled_set,
+};
+
+static int lis3lv02d_add(struct acpi_device *device)
+{
+ u8 val;
+ int ret;
+
+ if (!device)
+ return -EINVAL;
+
+ adev.device = device;
+ adev.init = lis3lv02d_acpi_init;
+ adev.read = lis3lv02d_acpi_read;
+ adev.write = lis3lv02d_acpi_write;
+ strcpy(acpi_device_name(device), DRIVER_NAME);
+ strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
+ device->driver_data = &adev;
+
+ lis3lv02d_acpi_read(device->handle, WHO_AM_I, &val);
+ if ((val != LIS3LV02DL_ID) && (val != LIS302DL_ID)) {
+ printk(KERN_ERR DRIVER_NAME
+ ": Accelerometer chip not LIS3LV02D{L,Q}\n");
+ }
+
+ /* If possible use a "standard" axes order */
+ if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
+ printk(KERN_INFO DRIVER_NAME ": laptop model unknown, "
+ "using default axes configuration\n");
+ adev.ac = lis3lv02d_axis_normal;
+ }
+
+ INIT_WORK(&hpled_led.work, delayed_set_status_worker);
+ ret = led_classdev_register(NULL, &hpled_led.led_classdev);
+ if (ret)
+ return ret;
+
+ ret = lis3lv02d_init_device(&adev);
+ if (ret) {
+ flush_work(&hpled_led.work);
+ led_classdev_unregister(&hpled_led.led_classdev);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int lis3lv02d_remove(struct acpi_device *device, int type)
+{
+ if (!device)
+ return -EINVAL;
+
+ lis3lv02d_joystick_disable();
+ lis3lv02d_poweroff(device->handle);
+
+ flush_work(&hpled_led.work);
+ led_classdev_unregister(&hpled_led.led_classdev);
+
+ return lis3lv02d_remove_fs();
+}
+
+
+#ifdef CONFIG_PM
+static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
+{
+ /* make sure the device is off when we suspend */
+ lis3lv02d_poweroff(device->handle);
+ return 0;
+}
+
+static int lis3lv02d_resume(struct acpi_device *device)
+{
+ /* put back the device in the right state (ACPI might turn it on) */
+ mutex_lock(&adev.lock);
+ if (adev.usage > 0)
+ lis3lv02d_poweron(device->handle);
+ else
+ lis3lv02d_poweroff(device->handle);
+ mutex_unlock(&adev.lock);
+ return 0;
+}
+#else
+#define lis3lv02d_suspend NULL
+#define lis3lv02d_resume NULL
+#endif
+
+/* For the HP MDPS aka 3D Driveguard */
+static struct acpi_driver lis3lv02d_driver = {
+ .name = DRIVER_NAME,
+ .class = ACPI_MDPS_CLASS,
+ .ids = lis3lv02d_device_ids,
+ .ops = {
+ .add = lis3lv02d_add,
+ .remove = lis3lv02d_remove,
+ .suspend = lis3lv02d_suspend,
+ .resume = lis3lv02d_resume,
+ }
+};
+
+static int __init lis3lv02d_init_module(void)
+{
+ int ret;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ ret = acpi_bus_register_driver(&lis3lv02d_driver);
+ if (ret < 0)
+ return ret;
+
+ printk(KERN_INFO DRIVER_NAME " driver loaded.\n");
+
+ return 0;
+}
+
+static void __exit lis3lv02d_exit_module(void)
+{
+ acpi_bus_unregister_driver(&lis3lv02d_driver);
+}
+
+MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS and support for disk protection LED.");
+MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
+MODULE_LICENSE("GPL");
+
+module_init(lis3lv02d_init_module);
+module_exit(lis3lv02d_exit_module);
+
diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c
index 2ede9388096b..27d7f72a5f11 100644
--- a/drivers/hwmon/i5k_amb.c
+++ b/drivers/hwmon/i5k_amb.c
@@ -490,6 +490,13 @@ static unsigned long chipset_ids[] = {
0
};
+static struct pci_device_id i5k_amb_ids[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5000_ERR) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, i5k_amb_ids);
+
static int __devinit i5k_amb_probe(struct platform_device *pdev)
{
struct i5k_amb_data *data;
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index b74c95735f95..95a99c590da2 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -14,6 +14,7 @@
IT8712F Super I/O chip w/LPC interface
IT8716F Super I/O chip w/LPC interface
IT8718F Super I/O chip w/LPC interface
+ IT8720F Super I/O chip w/LPC interface
IT8726F Super I/O chip w/LPC interface
Sis950 A clone of the IT8705F
@@ -48,11 +49,12 @@
#include <linux/sysfs.h>
#include <linux/string.h>
#include <linux/dmi.h>
+#include <linux/acpi.h>
#include <asm/io.h>
#define DRVNAME "it87"
-enum chips { it87, it8712, it8716, it8718 };
+enum chips { it87, it8712, it8716, it8718, it8720 };
static unsigned short force_id;
module_param(force_id, ushort, 0);
@@ -64,7 +66,10 @@ static struct platform_device *pdev;
#define DEV 0x07 /* Register: Logical device select */
#define VAL 0x2f /* The value to read/write */
#define PME 0x04 /* The device with the fan registers in it */
-#define GPIO 0x07 /* The device with the IT8718F VID value in it */
+
+/* The device with the IT8718F/IT8720F VID value in it */
+#define GPIO 0x07
+
#define DEVID 0x20 /* Register: Device ID */
#define DEVREV 0x22 /* Register: Device Revision */
@@ -113,6 +118,7 @@ superio_exit(void)
#define IT8705F_DEVID 0x8705
#define IT8716F_DEVID 0x8716
#define IT8718F_DEVID 0x8718
+#define IT8720F_DEVID 0x8720
#define IT8726F_DEVID 0x8726
#define IT87_ACT_REG 0x30
#define IT87_BASE_REG 0x60
@@ -150,8 +156,8 @@ static int fix_pwm_polarity;
#define IT87_REG_ALARM2 0x02
#define IT87_REG_ALARM3 0x03
-/* The IT8718F has the VID value in a different register, in Super-I/O
- configuration space. */
+/* The IT8718F and IT8720F have the VID value in a different register, in
+ Super-I/O configuration space. */
#define IT87_REG_VID 0x0a
/* The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b
for fan divisors. Later IT8712F revisions must use 16-bit tachometer
@@ -282,7 +288,8 @@ static inline int has_16bit_fans(const struct it87_data *data)
return (data->type == it87 && data->revision >= 0x03)
|| (data->type == it8712 && data->revision >= 0x08)
|| data->type == it8716
- || data->type == it8718;
+ || data->type == it8718
+ || data->type == it8720;
}
static int it87_probe(struct platform_device *pdev);
@@ -992,6 +999,9 @@ static int __init it87_find(unsigned short *address,
case IT8718F_DEVID:
sio_data->type = it8718;
break;
+ case IT8720F_DEVID:
+ sio_data->type = it8720;
+ break;
case 0xffff: /* No device at all */
goto exit;
default:
@@ -1022,7 +1032,8 @@ static int __init it87_find(unsigned short *address,
int reg;
superio_select(GPIO);
- if (chip_type == it8718)
+ if ((chip_type == it8718) ||
+ (chip_type == it8720))
sio_data->vid_value = superio_inb(IT87_SIO_VID_REG);
reg = superio_inb(IT87_SIO_PINX2_REG);
@@ -1068,6 +1079,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
"it8712",
"it8716",
"it8718",
+ "it8720",
};
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1226,7 +1238,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
}
if (data->type == it8712 || data->type == it8716
- || data->type == it8718) {
+ || data->type == it8718 || data->type == it8720) {
data->vrm = vid_which_vrm();
/* VID reading from Super-I/O config space if available */
data->vid = sio_data->vid_value;
@@ -1374,7 +1386,7 @@ static void __devinit it87_init_device(struct platform_device *pdev)
it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
}
- /* Check if temperature channnels are reset manually or by some reason */
+ /* Check if temperature channels are reset manually or by some reason */
tmp = it87_read_value(data, IT87_REG_TEMP_ENABLE);
if ((tmp & 0x3f) == 0) {
/* Temp1,Temp3=thermistor; Temp2=thermal diode */
@@ -1513,7 +1525,8 @@ static struct it87_data *it87_update_device(struct device *dev)
data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
/* The 8705 does not have VID capability.
- The 8718 does not use IT87_REG_VID for the same purpose. */
+ The 8718 and the 8720 don't use IT87_REG_VID for the
+ same purpose. */
if (data->type == it8712 || data->type == it8716) {
data->vid = it87_read_value(data, IT87_REG_VID);
/* The older IT8712F revisions had only 5 VID pins,
@@ -1540,6 +1553,10 @@ static int __init it87_device_add(unsigned short address,
};
int err;
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto exit;
+
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev) {
err = -ENOMEM;
@@ -1608,7 +1625,7 @@ static void __exit sm_it87_exit(void)
MODULE_AUTHOR("Chris Gauthron, "
"Jean Delvare <khali@linux-fr.org>");
-MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8726F, SiS950 driver");
+MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8720F/8726F, SiS950 driver");
module_param(update_vbat, bool, 0);
MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
module_param(fix_pwm_polarity, bool, 0);
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
index bd2bde0ef95e..1fe995111841 100644
--- a/drivers/hwmon/k8temp.c
+++ b/drivers/hwmon/k8temp.c
@@ -31,6 +31,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <asm/processor.h>
#define TEMP_FROM_REG(val) (((((val) >> 16) & 0xff) - 49) * 1000)
#define REG_TEMP 0xe4
@@ -47,6 +48,8 @@ struct k8temp_data {
/* registers values */
u8 sensorsp; /* sensor presence bits - SEL_CORE & SEL_PLACE */
u32 temp[2][2]; /* core, place */
+ u8 swap_core_select; /* meaning of SEL_CORE is inverted */
+ u32 temp_offset;
};
static struct k8temp_data *k8temp_update_device(struct device *dev)
@@ -114,10 +117,15 @@ static ssize_t show_temp(struct device *dev,
to_sensor_dev_attr_2(devattr);
int core = attr->nr;
int place = attr->index;
+ int temp;
struct k8temp_data *data = k8temp_update_device(dev);
- return sprintf(buf, "%d\n",
- TEMP_FROM_REG(data->temp[core][place]));
+ if (data->swap_core_select)
+ core = core ? 0 : 1;
+
+ temp = TEMP_FROM_REG(data->temp[core][place]) + data->temp_offset;
+
+ return sprintf(buf, "%d\n", temp);
}
/* core, place */
@@ -141,20 +149,49 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
int err;
u8 scfg;
u32 temp;
+ u8 model, stepping;
struct k8temp_data *data;
- u32 cpuid = cpuid_eax(1);
-
- /* this feature should be available since SH-C0 core */
- if ((cpuid == 0xf40) || (cpuid == 0xf50) || (cpuid == 0xf51)) {
- err = -ENODEV;
- goto exit;
- }
if (!(data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
+ model = boot_cpu_data.x86_model;
+ stepping = boot_cpu_data.x86_mask;
+
+ switch (boot_cpu_data.x86) {
+ case 0xf:
+ /* feature available since SH-C0, exclude older revisions */
+ if (((model == 4) && (stepping == 0)) ||
+ ((model == 5) && (stepping <= 1))) {
+ err = -ENODEV;
+ goto exit_free;
+ }
+
+ /*
+ * AMD NPT family 0fh, i.e. RevF and RevG:
+ * meaning of SEL_CORE bit is inverted
+ */
+ if (model >= 0x40) {
+ data->swap_core_select = 1;
+ dev_warn(&pdev->dev, "Temperature readouts might be "
+ "wrong - check erratum #141\n");
+ }
+
+ if ((model >= 0x69) &&
+ !(model == 0xc1 || model == 0x6c || model == 0x7c)) {
+ /*
+ * RevG desktop CPUs (i.e. no socket S1G1 parts)
+ * need additional offset, otherwise reported
+ * temperature is below ambient temperature
+ */
+ data->temp_offset = 21000;
+ }
+
+ break;
+ }
+
pci_read_config_byte(pdev, REG_TEMP, &scfg);
scfg &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */
pci_write_config_byte(pdev, REG_TEMP, scfg);
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c
index c002144c76bc..219d2d0d5a62 100644
--- a/drivers/hwmon/lis3lv02d.c
+++ b/drivers/hwmon/lis3lv02d.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2007-2008 Yan Burman
* Copyright (C) 2008 Eric Piel
+ * Copyright (C) 2008 Pavel Machek
*
* 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
@@ -39,7 +40,6 @@
#include "lis3lv02d.h"
#define DRIVER_NAME "lis3lv02d"
-#define ACPI_MDPS_CLASS "accelerometer"
/* joystick device poll interval in milliseconds */
#define MDPS_POLL_INTERVAL 50
@@ -55,100 +55,17 @@
/* Maximum value our axis may get for the input device (signed 12 bits) */
#define MDPS_MAX_VAL 2048
-struct axis_conversion {
- s8 x;
- s8 y;
- s8 z;
-};
-
-struct acpi_lis3lv02d {
- struct acpi_device *device; /* The ACPI device */
- struct input_dev *idev; /* input device */
- struct task_struct *kthread; /* kthread for input */
- struct mutex lock;
- struct platform_device *pdev; /* platform device */
- atomic_t count; /* interrupt count after last read */
- int xcalib; /* calibrated null value for x */
- int ycalib; /* calibrated null value for y */
- int zcalib; /* calibrated null value for z */
- unsigned char is_on; /* whether the device is on or off */
- unsigned char usage; /* usage counter */
- struct axis_conversion ac; /* hw -> logical axis */
-};
+struct acpi_lis3lv02d adev;
+EXPORT_SYMBOL_GPL(adev);
-static struct acpi_lis3lv02d adev;
-
-static int lis3lv02d_remove_fs(void);
static int lis3lv02d_add_fs(struct acpi_device *device);
-/* For automatic insertion of the module */
-static struct acpi_device_id lis3lv02d_device_ids[] = {
- {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
- {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
-
-/**
- * lis3lv02d_acpi_init - ACPI _INI method: initialize the device.
- * @handle: the handle of the device
- *
- * Returns AE_OK on success.
- */
-static inline acpi_status lis3lv02d_acpi_init(acpi_handle handle)
-{
- return acpi_evaluate_object(handle, METHOD_NAME__INI, NULL, NULL);
-}
-
-/**
- * lis3lv02d_acpi_read - ACPI ALRD method: read a register
- * @handle: the handle of the device
- * @reg: the register to read
- * @ret: result of the operation
- *
- * Returns AE_OK on success.
- */
-static acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret)
-{
- union acpi_object arg0 = { ACPI_TYPE_INTEGER };
- struct acpi_object_list args = { 1, &arg0 };
- unsigned long long lret;
- acpi_status status;
-
- arg0.integer.value = reg;
-
- status = acpi_evaluate_integer(handle, "ALRD", &args, &lret);
- *ret = lret;
- return status;
-}
-
-/**
- * lis3lv02d_acpi_write - ACPI ALWR method: write to a register
- * @handle: the handle of the device
- * @reg: the register to write to
- * @val: the value to write
- *
- * Returns AE_OK on success.
- */
-static acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val)
-{
- unsigned long long ret; /* Not used when writting */
- union acpi_object in_obj[2];
- struct acpi_object_list args = { 2, in_obj };
-
- in_obj[0].type = ACPI_TYPE_INTEGER;
- in_obj[0].integer.value = reg;
- in_obj[1].type = ACPI_TYPE_INTEGER;
- in_obj[1].integer.value = val;
-
- return acpi_evaluate_integer(handle, "ALWR", &args, &ret);
-}
-
static s16 lis3lv02d_read_16(acpi_handle handle, int reg)
{
u8 lo, hi;
- lis3lv02d_acpi_read(handle, reg, &lo);
- lis3lv02d_acpi_read(handle, reg + 1, &hi);
+ adev.read(handle, reg, &lo);
+ adev.read(handle, reg + 1, &hi);
/* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
return (s16)((hi << 8) | lo);
}
@@ -190,54 +107,31 @@ static void lis3lv02d_get_xyz(acpi_handle handle, int *x, int *y, int *z)
*z = lis3lv02d_get_axis(adev.ac.z, position);
}
-static inline void lis3lv02d_poweroff(acpi_handle handle)
+void lis3lv02d_poweroff(acpi_handle handle)
{
adev.is_on = 0;
/* disable X,Y,Z axis and power down */
- lis3lv02d_acpi_write(handle, CTRL_REG1, 0x00);
+ adev.write(handle, CTRL_REG1, 0x00);
}
+EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
-static void lis3lv02d_poweron(acpi_handle handle)
+void lis3lv02d_poweron(acpi_handle handle)
{
u8 val;
adev.is_on = 1;
- lis3lv02d_acpi_init(handle);
- lis3lv02d_acpi_write(handle, FF_WU_CFG, 0);
+ adev.init(handle);
+ adev.write(handle, FF_WU_CFG, 0);
/*
* BDU: LSB and MSB values are not updated until both have been read.
* So the value read will always be correct.
* IEN: Interrupt for free-fall and DD, not for data-ready.
*/
- lis3lv02d_acpi_read(handle, CTRL_REG2, &val);
+ adev.read(handle, CTRL_REG2, &val);
val |= CTRL2_BDU | CTRL2_IEN;
- lis3lv02d_acpi_write(handle, CTRL_REG2, val);
-}
-
-#ifdef CONFIG_PM
-static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
-{
- /* make sure the device is off when we suspend */
- lis3lv02d_poweroff(device->handle);
- return 0;
-}
-
-static int lis3lv02d_resume(struct acpi_device *device)
-{
- /* put back the device in the right state (ACPI might turn it on) */
- mutex_lock(&adev.lock);
- if (adev.usage > 0)
- lis3lv02d_poweron(device->handle);
- else
- lis3lv02d_poweroff(device->handle);
- mutex_unlock(&adev.lock);
- return 0;
+ adev.write(handle, CTRL_REG2, val);
}
-#else
-#define lis3lv02d_suspend NULL
-#define lis3lv02d_resume NULL
-#endif
-
+EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
/*
* To be called before starting to use the device. It makes sure that the
@@ -315,7 +209,7 @@ static inline void lis3lv02d_calibrate_joystick(void)
lis3lv02d_get_xyz(adev.device->handle, &adev.xcalib, &adev.ycalib, &adev.zcalib);
}
-static int lis3lv02d_joystick_enable(void)
+int lis3lv02d_joystick_enable(void)
{
int err;
@@ -349,8 +243,9 @@ static int lis3lv02d_joystick_enable(void)
return err;
}
+EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable);
-static void lis3lv02d_joystick_disable(void)
+void lis3lv02d_joystick_disable(void)
{
if (!adev.idev)
return;
@@ -358,13 +253,13 @@ static void lis3lv02d_joystick_disable(void)
input_unregister_device(adev.idev);
adev.idev = NULL;
}
-
+EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
/*
* Initialise the accelerometer and the various subsystems.
* Should be rather independant of the bus system.
*/
-static int lis3lv02d_init_device(struct acpi_lis3lv02d *dev)
+int lis3lv02d_init_device(struct acpi_lis3lv02d *dev)
{
mutex_init(&dev->lock);
lis3lv02d_add_fs(dev->device);
@@ -376,93 +271,7 @@ static int lis3lv02d_init_device(struct acpi_lis3lv02d *dev)
lis3lv02d_decrease_use(dev);
return 0;
}
-
-static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
-{
- adev.ac = *((struct axis_conversion *)dmi->driver_data);
- printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident);
-
- return 1;
-}
-
-/* Represents, for each axis seen by userspace, the corresponding hw axis (+1).
- * If the value is negative, the opposite of the hw value is used. */
-static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3};
-static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3};
-static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3};
-static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3};
-static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3};
-static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3};
-
-#define AXIS_DMI_MATCH(_ident, _name, _axis) { \
- .ident = _ident, \
- .callback = lis3lv02d_dmi_matched, \
- .matches = { \
- DMI_MATCH(DMI_PRODUCT_NAME, _name) \
- }, \
- .driver_data = &lis3lv02d_axis_##_axis \
-}
-static struct dmi_system_id lis3lv02d_dmi_ids[] = {
- /* product names are truncated to match all kinds of a same model */
- AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted),
- AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted),
- AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted),
- AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted),
- AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted),
- AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted),
- AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left),
- { NULL, }
-/* Laptop models without axis info (yet):
- * "NC651xx" "HP Compaq 651"
- * "NC671xx" "HP Compaq 671"
- * "NC6910" "HP Compaq 6910"
- * HP Compaq 8710x Notebook PC / Mobile Workstation
- * "NC2400" "HP Compaq nc2400"
- * "NX74x0" "HP Compaq nx74"
- * "NX6325" "HP Compaq nx6325"
- * "NC4400" "HP Compaq nc4400"
- */
-};
-
-static int lis3lv02d_add(struct acpi_device *device)
-{
- u8 val;
-
- if (!device)
- return -EINVAL;
-
- adev.device = device;
- strcpy(acpi_device_name(device), DRIVER_NAME);
- strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
- device->driver_data = &adev;
-
- lis3lv02d_acpi_read(device->handle, WHO_AM_I, &val);
- if ((val != LIS3LV02DL_ID) && (val != LIS302DL_ID)) {
- printk(KERN_ERR DRIVER_NAME
- ": Accelerometer chip not LIS3LV02D{L,Q}\n");
- }
-
- /* If possible use a "standard" axes order */
- if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
- printk(KERN_INFO DRIVER_NAME ": laptop model unknown, "
- "using default axes configuration\n");
- adev.ac = lis3lv02d_axis_normal;
- }
-
- return lis3lv02d_init_device(&adev);
-}
-
-static int lis3lv02d_remove(struct acpi_device *device, int type)
-{
- if (!device)
- return -EINVAL;
-
- lis3lv02d_joystick_disable();
- lis3lv02d_poweroff(device->handle);
-
- return lis3lv02d_remove_fs();
-}
-
+EXPORT_SYMBOL_GPL(lis3lv02d_init_device);
/* Sysfs stuff */
static ssize_t lis3lv02d_position_show(struct device *dev,
@@ -501,7 +310,7 @@ static ssize_t lis3lv02d_rate_show(struct device *dev,
int val;
lis3lv02d_increase_use(&adev);
- lis3lv02d_acpi_read(adev.device->handle, CTRL_REG1, &ctrl);
+ adev.read(adev.device->handle, CTRL_REG1, &ctrl);
lis3lv02d_decrease_use(&adev);
val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4;
return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]);
@@ -523,6 +332,7 @@ static struct attribute_group lis3lv02d_attribute_group = {
.attrs = lis3lv02d_attributes
};
+
static int lis3lv02d_add_fs(struct acpi_device *device)
{
adev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
@@ -532,50 +342,15 @@ static int lis3lv02d_add_fs(struct acpi_device *device)
return sysfs_create_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group);
}
-static int lis3lv02d_remove_fs(void)
+int lis3lv02d_remove_fs(void)
{
sysfs_remove_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group);
platform_device_unregister(adev.pdev);
return 0;
}
-
-/* For the HP MDPS aka 3D Driveguard */
-static struct acpi_driver lis3lv02d_driver = {
- .name = DRIVER_NAME,
- .class = ACPI_MDPS_CLASS,
- .ids = lis3lv02d_device_ids,
- .ops = {
- .add = lis3lv02d_add,
- .remove = lis3lv02d_remove,
- .suspend = lis3lv02d_suspend,
- .resume = lis3lv02d_resume,
- }
-};
-
-static int __init lis3lv02d_init_module(void)
-{
- int ret;
-
- if (acpi_disabled)
- return -ENODEV;
-
- ret = acpi_bus_register_driver(&lis3lv02d_driver);
- if (ret < 0)
- return ret;
-
- printk(KERN_INFO DRIVER_NAME " driver loaded.\n");
-
- return 0;
-}
-
-static void __exit lis3lv02d_exit_module(void)
-{
- acpi_bus_unregister_driver(&lis3lv02d_driver);
-}
+EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver");
MODULE_AUTHOR("Yan Burman and Eric Piel");
MODULE_LICENSE("GPL");
-module_init(lis3lv02d_init_module);
-module_exit(lis3lv02d_exit_module);
diff --git a/drivers/hwmon/lis3lv02d.h b/drivers/hwmon/lis3lv02d.h
index 330cfc60e948..223f1c0763bb 100644
--- a/drivers/hwmon/lis3lv02d.h
+++ b/drivers/hwmon/lis3lv02d.h
@@ -23,7 +23,7 @@
* The actual chip is STMicroelectronics LIS3LV02DL or LIS3LV02DQ that seems to
* be connected via SPI. There exists also several similar chips (such as LIS302DL or
* LIS3L02DQ) but not in the HP laptops and they have slightly different registers.
- * They can also be connected via I²C.
+ * They can also be connected via I²C.
*/
#define LIS3LV02DL_ID 0x3A /* Also the LIS3LV02DQ */
@@ -147,3 +147,36 @@ enum lis3lv02d_dd_src {
DD_SRC_IA = 0x40,
};
+struct axis_conversion {
+ s8 x;
+ s8 y;
+ s8 z;
+};
+
+struct acpi_lis3lv02d {
+ struct acpi_device *device; /* The ACPI device */
+ acpi_status (*init) (acpi_handle handle);
+ acpi_status (*write) (acpi_handle handle, int reg, u8 val);
+ acpi_status (*read) (acpi_handle handle, int reg, u8 *ret);
+
+ struct input_dev *idev; /* input device */
+ struct task_struct *kthread; /* kthread for input */
+ struct mutex lock;
+ struct platform_device *pdev; /* platform device */
+ atomic_t count; /* interrupt count after last read */
+ int xcalib; /* calibrated null value for x */
+ int ycalib; /* calibrated null value for y */
+ int zcalib; /* calibrated null value for z */
+ unsigned char is_on; /* whether the device is on or off */
+ unsigned char usage; /* usage counter */
+ struct axis_conversion ac; /* hw -> logical axis */
+};
+
+int lis3lv02d_init_device(struct acpi_lis3lv02d *dev);
+int lis3lv02d_joystick_enable(void);
+void lis3lv02d_joystick_disable(void);
+void lis3lv02d_poweroff(acpi_handle handle);
+void lis3lv02d_poweron(acpi_handle handle);
+int lis3lv02d_remove_fs(void);
+
+extern struct acpi_lis3lv02d adev;
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
index d435f003292d..ae6204f33214 100644
--- a/drivers/hwmon/lm70.c
+++ b/drivers/hwmon/lm70.c
@@ -37,9 +37,13 @@
#define DRVNAME "lm70"
+#define LM70_CHIP_LM70 0 /* original NS LM70 */
+#define LM70_CHIP_TMP121 1 /* TI TMP121/TMP123 */
+
struct lm70 {
struct device *hwmon_dev;
struct mutex lock;
+ unsigned int chip;
};
/* sysfs hook function */
@@ -47,7 +51,7 @@ static ssize_t lm70_sense_temp(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct spi_device *spi = to_spi_device(dev);
- int status, val;
+ int status, val = 0;
u8 rxbuf[2];
s16 raw=0;
struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
@@ -65,12 +69,12 @@ static ssize_t lm70_sense_temp(struct device *dev,
"spi_write_then_read failed with status %d\n", status);
goto out;
}
- dev_dbg(dev, "rxbuf[1] : 0x%x rxbuf[0] : 0x%x\n", rxbuf[1], rxbuf[0]);
-
- raw = (rxbuf[1] << 8) + rxbuf[0];
- dev_dbg(dev, "raw=0x%x\n", raw);
+ raw = (rxbuf[0] << 8) + rxbuf[1];
+ dev_dbg(dev, "rxbuf[0] : 0x%02x rxbuf[1] : 0x%02x raw=0x%04x\n",
+ rxbuf[0], rxbuf[1], raw);
/*
+ * LM70:
* The "raw" temperature read into rxbuf[] is a 16-bit signed 2's
* complement value. Only the MSB 11 bits (1 sign + 10 temperature
* bits) are meaningful; the LSB 5 bits are to be discarded.
@@ -80,8 +84,21 @@ static ssize_t lm70_sense_temp(struct device *dev,
* by 0.25. Also multiply by 1000 to represent in millidegrees
* Celsius.
* So it's equivalent to multiplying by 0.25 * 1000 = 250.
+ *
+ * TMP121/TMP123:
+ * 13 bits of 2's complement data, discard LSB 3 bits,
+ * resolution 0.0625 degrees celsius.
*/
- val = ((int)raw/32) * 250;
+ switch (p_lm70->chip) {
+ case LM70_CHIP_LM70:
+ val = ((int)raw / 32) * 250;
+ break;
+
+ case LM70_CHIP_TMP121:
+ val = ((int)raw / 8) * 625 / 10;
+ break;
+ }
+
status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */
out:
mutex_unlock(&p_lm70->lock);
@@ -93,27 +110,39 @@ static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL);
static ssize_t lm70_show_name(struct device *dev, struct device_attribute
*devattr, char *buf)
{
- return sprintf(buf, "lm70\n");
+ struct lm70 *p_lm70 = dev_get_drvdata(dev);
+ int ret;
+
+ switch (p_lm70->chip) {
+ case LM70_CHIP_LM70:
+ ret = sprintf(buf, "lm70\n");
+ break;
+ case LM70_CHIP_TMP121:
+ ret = sprintf(buf, "tmp121\n");
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
}
static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL);
/*----------------------------------------------------------------------*/
-static int __devinit lm70_probe(struct spi_device *spi)
+static int __devinit common_probe(struct spi_device *spi, int chip)
{
struct lm70 *p_lm70;
int status;
- /* signaling is SPI_MODE_0 on a 3-wire link (shared SI/SO) */
- if ((spi->mode & (SPI_CPOL|SPI_CPHA)) || !(spi->mode & SPI_3WIRE))
- return -EINVAL;
+ /* NOTE: we assume 8-bit words, and convert to 16 bits manually */
p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL);
if (!p_lm70)
return -ENOMEM;
mutex_init(&p_lm70->lock);
+ p_lm70->chip = chip;
/* sysfs hook */
p_lm70->hwmon_dev = hwmon_device_register(&spi->dev);
@@ -141,6 +170,24 @@ out_dev_reg_failed:
return status;
}
+static int __devinit lm70_probe(struct spi_device *spi)
+{
+ /* signaling is SPI_MODE_0 on a 3-wire link (shared SI/SO) */
+ if ((spi->mode & (SPI_CPOL | SPI_CPHA)) || !(spi->mode & SPI_3WIRE))
+ return -EINVAL;
+
+ return common_probe(spi, LM70_CHIP_LM70);
+}
+
+static int __devinit tmp121_probe(struct spi_device *spi)
+{
+ /* signaling is SPI_MODE_0 with only MISO connected */
+ if (spi->mode & (SPI_CPOL | SPI_CPHA))
+ return -EINVAL;
+
+ return common_probe(spi, LM70_CHIP_TMP121);
+}
+
static int __devexit lm70_remove(struct spi_device *spi)
{
struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
@@ -154,6 +201,15 @@ static int __devexit lm70_remove(struct spi_device *spi)
return 0;
}
+static struct spi_driver tmp121_driver = {
+ .driver = {
+ .name = "tmp121",
+ .owner = THIS_MODULE,
+ },
+ .probe = tmp121_probe,
+ .remove = __devexit_p(lm70_remove),
+};
+
static struct spi_driver lm70_driver = {
.driver = {
.name = "lm70",
@@ -165,17 +221,26 @@ static struct spi_driver lm70_driver = {
static int __init init_lm70(void)
{
- return spi_register_driver(&lm70_driver);
+ int ret = spi_register_driver(&lm70_driver);
+ if (ret)
+ return ret;
+
+ ret = spi_register_driver(&tmp121_driver);
+ if (ret)
+ spi_unregister_driver(&lm70_driver);
+
+ return ret;
}
static void __exit cleanup_lm70(void)
{
spi_unregister_driver(&lm70_driver);
+ spi_unregister_driver(&tmp121_driver);
}
module_init(init_lm70);
module_exit(cleanup_lm70);
MODULE_AUTHOR("Kaiwan N Billimoria");
-MODULE_DESCRIPTION("National Semiconductor LM70 Linux driver");
+MODULE_DESCRIPTION("NS LM70 / TI TMP121/TMP123 Linux driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c
new file mode 100644
index 000000000000..034b2c515848
--- /dev/null
+++ b/drivers/hwmon/ltc4245.c
@@ -0,0 +1,567 @@
+/*
+ * Driver for Linear Technology LTC4245 I2C Multiple Supply Hot Swap Controller
+ *
+ * Copyright (C) 2008 Ira W. Snyder <iws@ovro.caltech.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
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This driver is based on the ds1621 and ina209 drivers.
+ *
+ * Datasheet:
+ * http://www.linear.com/pc/downloadDocument.do?navId=H0,C1,C1003,C1006,C1140,P19392,D13517
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+/* Valid addresses are 0x20 - 0x3f
+ *
+ * For now, we do not probe, since some of these addresses
+ * are known to be unfriendly to probing */
+static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(ltc4245);
+
+/* Here are names of the chip's registers (a.k.a. commands) */
+enum ltc4245_cmd {
+ LTC4245_STATUS = 0x00, /* readonly */
+ LTC4245_ALERT = 0x01,
+ LTC4245_CONTROL = 0x02,
+ LTC4245_ON = 0x03,
+ LTC4245_FAULT1 = 0x04,
+ LTC4245_FAULT2 = 0x05,
+ LTC4245_GPIO = 0x06,
+ LTC4245_ADCADR = 0x07,
+
+ LTC4245_12VIN = 0x10,
+ LTC4245_12VSENSE = 0x11,
+ LTC4245_12VOUT = 0x12,
+ LTC4245_5VIN = 0x13,
+ LTC4245_5VSENSE = 0x14,
+ LTC4245_5VOUT = 0x15,
+ LTC4245_3VIN = 0x16,
+ LTC4245_3VSENSE = 0x17,
+ LTC4245_3VOUT = 0x18,
+ LTC4245_VEEIN = 0x19,
+ LTC4245_VEESENSE = 0x1a,
+ LTC4245_VEEOUT = 0x1b,
+ LTC4245_GPIOADC1 = 0x1c,
+ LTC4245_GPIOADC2 = 0x1d,
+ LTC4245_GPIOADC3 = 0x1e,
+};
+
+struct ltc4245_data {
+ struct device *hwmon_dev;
+
+ struct mutex update_lock;
+ bool valid;
+ unsigned long last_updated; /* in jiffies */
+
+ /* Control registers */
+ u8 cregs[0x08];
+
+ /* Voltage registers */
+ u8 vregs[0x0f];
+};
+
+static struct ltc4245_data *ltc4245_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ltc4245_data *data = i2c_get_clientdata(client);
+ s32 val;
+ int i;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+
+ dev_dbg(&client->dev, "Starting ltc4245 update\n");
+
+ /* Read control registers -- 0x00 to 0x07 */
+ for (i = 0; i < ARRAY_SIZE(data->cregs); i++) {
+ val = i2c_smbus_read_byte_data(client, i);
+ if (unlikely(val < 0))
+ data->cregs[i] = 0;
+ else
+ data->cregs[i] = val;
+ }
+
+ /* Read voltage registers -- 0x10 to 0x1f */
+ for (i = 0; i < ARRAY_SIZE(data->vregs); i++) {
+ val = i2c_smbus_read_byte_data(client, i+0x10);
+ if (unlikely(val < 0))
+ data->vregs[i] = 0;
+ else
+ data->vregs[i] = val;
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+/* Return the voltage from the given register in millivolts */
+static int ltc4245_get_voltage(struct device *dev, u8 reg)
+{
+ struct ltc4245_data *data = ltc4245_update_device(dev);
+ const u8 regval = data->vregs[reg - 0x10];
+ u32 voltage = 0;
+
+ switch (reg) {
+ case LTC4245_12VIN:
+ case LTC4245_12VOUT:
+ voltage = regval * 55;
+ break;
+ case LTC4245_5VIN:
+ case LTC4245_5VOUT:
+ voltage = regval * 22;
+ break;
+ case LTC4245_3VIN:
+ case LTC4245_3VOUT:
+ voltage = regval * 15;
+ break;
+ case LTC4245_VEEIN:
+ case LTC4245_VEEOUT:
+ voltage = regval * -55;
+ break;
+ case LTC4245_GPIOADC1:
+ case LTC4245_GPIOADC2:
+ case LTC4245_GPIOADC3:
+ voltage = regval * 10;
+ break;
+ default:
+ /* If we get here, the developer messed up */
+ WARN_ON_ONCE(1);
+ break;
+ }
+
+ return voltage;
+}
+
+/* Return the current in the given sense register in milliAmperes */
+static unsigned int ltc4245_get_current(struct device *dev, u8 reg)
+{
+ struct ltc4245_data *data = ltc4245_update_device(dev);
+ const u8 regval = data->vregs[reg - 0x10];
+ unsigned int voltage;
+ unsigned int curr;
+
+ /* The strange looking conversions that follow are fixed-point
+ * math, since we cannot do floating point in the kernel.
+ *
+ * Step 1: convert sense register to microVolts
+ * Step 2: convert voltage to milliAmperes
+ *
+ * If you play around with the V=IR equation, you come up with
+ * the following: X uV / Y mOhm == Z mA
+ *
+ * With the resistors that are fractions of a milliOhm, we multiply
+ * the voltage and resistance by 10, to shift the decimal point.
+ * Now we can use the normal division operator again.
+ */
+
+ switch (reg) {
+ case LTC4245_12VSENSE:
+ voltage = regval * 250; /* voltage in uV */
+ curr = voltage / 50; /* sense resistor 50 mOhm */
+ break;
+ case LTC4245_5VSENSE:
+ voltage = regval * 125; /* voltage in uV */
+ curr = (voltage * 10) / 35; /* sense resistor 3.5 mOhm */
+ break;
+ case LTC4245_3VSENSE:
+ voltage = regval * 125; /* voltage in uV */
+ curr = (voltage * 10) / 25; /* sense resistor 2.5 mOhm */
+ break;
+ case LTC4245_VEESENSE:
+ voltage = regval * 250; /* voltage in uV */
+ curr = voltage / 100; /* sense resistor 100 mOhm */
+ break;
+ default:
+ /* If we get here, the developer messed up */
+ WARN_ON_ONCE(1);
+ curr = 0;
+ break;
+ }
+
+ return curr;
+}
+
+static ssize_t ltc4245_show_voltage(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ const int voltage = ltc4245_get_voltage(dev, attr->index);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", voltage);
+}
+
+static ssize_t ltc4245_show_current(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ const unsigned int curr = ltc4245_get_current(dev, attr->index);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", curr);
+}
+
+static ssize_t ltc4245_show_power(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ const unsigned int curr = ltc4245_get_current(dev, attr->index);
+ const int output_voltage = ltc4245_get_voltage(dev, attr->index+1);
+
+ /* current in mA * voltage in mV == power in uW */
+ const unsigned int power = abs(output_voltage * curr);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", power);
+}
+
+static ssize_t ltc4245_show_alarm(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
+ struct ltc4245_data *data = ltc4245_update_device(dev);
+ const u8 reg = data->cregs[attr->index];
+ const u32 mask = attr->nr;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0);
+}
+
+/* These macros are used below in constructing device attribute objects
+ * for use with sysfs_create_group() to make a sysfs device file
+ * for each register.
+ */
+
+#define LTC4245_VOLTAGE(name, ltc4245_cmd_idx) \
+ static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+ ltc4245_show_voltage, NULL, ltc4245_cmd_idx)
+
+#define LTC4245_CURRENT(name, ltc4245_cmd_idx) \
+ static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+ ltc4245_show_current, NULL, ltc4245_cmd_idx)
+
+#define LTC4245_POWER(name, ltc4245_cmd_idx) \
+ static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+ ltc4245_show_power, NULL, ltc4245_cmd_idx)
+
+#define LTC4245_ALARM(name, mask, reg) \
+ static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \
+ ltc4245_show_alarm, NULL, (mask), reg)
+
+/* Construct a sensor_device_attribute structure for each register */
+
+/* Input voltages */
+LTC4245_VOLTAGE(in1_input, LTC4245_12VIN);
+LTC4245_VOLTAGE(in2_input, LTC4245_5VIN);
+LTC4245_VOLTAGE(in3_input, LTC4245_3VIN);
+LTC4245_VOLTAGE(in4_input, LTC4245_VEEIN);
+
+/* Input undervoltage alarms */
+LTC4245_ALARM(in1_min_alarm, (1 << 0), LTC4245_FAULT1);
+LTC4245_ALARM(in2_min_alarm, (1 << 1), LTC4245_FAULT1);
+LTC4245_ALARM(in3_min_alarm, (1 << 2), LTC4245_FAULT1);
+LTC4245_ALARM(in4_min_alarm, (1 << 3), LTC4245_FAULT1);
+
+/* Currents (via sense resistor) */
+LTC4245_CURRENT(curr1_input, LTC4245_12VSENSE);
+LTC4245_CURRENT(curr2_input, LTC4245_5VSENSE);
+LTC4245_CURRENT(curr3_input, LTC4245_3VSENSE);
+LTC4245_CURRENT(curr4_input, LTC4245_VEESENSE);
+
+/* Overcurrent alarms */
+LTC4245_ALARM(curr1_max_alarm, (1 << 4), LTC4245_FAULT1);
+LTC4245_ALARM(curr2_max_alarm, (1 << 5), LTC4245_FAULT1);
+LTC4245_ALARM(curr3_max_alarm, (1 << 6), LTC4245_FAULT1);
+LTC4245_ALARM(curr4_max_alarm, (1 << 7), LTC4245_FAULT1);
+
+/* Output voltages */
+LTC4245_VOLTAGE(in5_input, LTC4245_12VOUT);
+LTC4245_VOLTAGE(in6_input, LTC4245_5VOUT);
+LTC4245_VOLTAGE(in7_input, LTC4245_3VOUT);
+LTC4245_VOLTAGE(in8_input, LTC4245_VEEOUT);
+
+/* Power Bad alarms */
+LTC4245_ALARM(in5_min_alarm, (1 << 0), LTC4245_FAULT2);
+LTC4245_ALARM(in6_min_alarm, (1 << 1), LTC4245_FAULT2);
+LTC4245_ALARM(in7_min_alarm, (1 << 2), LTC4245_FAULT2);
+LTC4245_ALARM(in8_min_alarm, (1 << 3), LTC4245_FAULT2);
+
+/* GPIO voltages */
+LTC4245_VOLTAGE(in9_input, LTC4245_GPIOADC1);
+LTC4245_VOLTAGE(in10_input, LTC4245_GPIOADC2);
+LTC4245_VOLTAGE(in11_input, LTC4245_GPIOADC3);
+
+/* Power Consumption (virtual) */
+LTC4245_POWER(power1_input, LTC4245_12VSENSE);
+LTC4245_POWER(power2_input, LTC4245_5VSENSE);
+LTC4245_POWER(power3_input, LTC4245_3VSENSE);
+LTC4245_POWER(power4_input, LTC4245_VEESENSE);
+
+/* Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *ltc4245_attributes[] = {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+
+ &sensor_dev_attr_in1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_min_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_curr2_input.dev_attr.attr,
+ &sensor_dev_attr_curr3_input.dev_attr.attr,
+ &sensor_dev_attr_curr4_input.dev_attr.attr,
+
+ &sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_curr3_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_curr4_max_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+
+ &sensor_dev_attr_in5_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in6_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in7_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_in8_min_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in9_input.dev_attr.attr,
+ &sensor_dev_attr_in10_input.dev_attr.attr,
+ &sensor_dev_attr_in11_input.dev_attr.attr,
+
+ &sensor_dev_attr_power1_input.dev_attr.attr,
+ &sensor_dev_attr_power2_input.dev_attr.attr,
+ &sensor_dev_attr_power3_input.dev_attr.attr,
+ &sensor_dev_attr_power4_input.dev_attr.attr,
+
+ NULL,
+};
+
+static const struct attribute_group ltc4245_group = {
+ .attrs = ltc4245_attributes,
+};
+
+static int ltc4245_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ltc4245_data *data;
+ int ret;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto out_kzalloc;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* Initialize the LTC4245 chip */
+ /* TODO */
+
+ /* Register sysfs hooks */
+ ret = sysfs_create_group(&client->dev.kobj, &ltc4245_group);
+ if (ret)
+ goto out_sysfs_create_group;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ goto out_hwmon_device_register;
+ }
+
+ return 0;
+
+out_hwmon_device_register:
+ sysfs_remove_group(&client->dev.kobj, &ltc4245_group);
+out_sysfs_create_group:
+ kfree(data);
+out_kzalloc:
+ return ret;
+}
+
+static int ltc4245_remove(struct i2c_client *client)
+{
+ struct ltc4245_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &ltc4245_group);
+
+ kfree(data);
+
+ return 0;
+}
+
+/* Check that some bits in a control register appear at all possible
+ * locations without changing value
+ *
+ * @client: the i2c client to use
+ * @reg: the register to read
+ * @bits: the bits to check (0xff checks all bits,
+ * 0x03 checks only the last two bits)
+ *
+ * return -ERRNO if the register read failed
+ * return -ENODEV if the register value doesn't stay constant at all
+ * possible addresses
+ *
+ * return 0 for success
+ */
+static int ltc4245_check_control_reg(struct i2c_client *client, u8 reg, u8 bits)
+{
+ int i;
+ s32 v, voff1, voff2;
+
+ /* Read register and check for error */
+ v = i2c_smbus_read_byte_data(client, reg);
+ if (v < 0)
+ return v;
+
+ v &= bits;
+
+ for (i = 0x00; i < 0xff; i += 0x20) {
+
+ voff1 = i2c_smbus_read_byte_data(client, reg + i);
+ if (voff1 < 0)
+ return voff1;
+
+ voff2 = i2c_smbus_read_byte_data(client, reg + i + 0x08);
+ if (voff2 < 0)
+ return voff2;
+
+ voff1 &= bits;
+ voff2 &= bits;
+
+ if (v != voff1 || v != voff2)
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int ltc4245_detect(struct i2c_client *client,
+ int kind,
+ struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = client->adapter;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ if (kind < 0) { /* probed detection - check the chip type */
+ s32 v; /* 8 bits from the chip, or -ERRNO */
+
+ /* Chip registers 0x00-0x07 are control registers
+ * Chip registers 0x10-0x1f are data registers
+ *
+ * Address bits b7-b5 are ignored. This makes the chip "repeat"
+ * in steps of 0x20. Any control registers should appear with
+ * the same values across all duplicated addresses.
+ *
+ * Register 0x02 bit b2 is reserved, expect 0
+ * Register 0x07 bits b7 to b4 are reserved, expect 0
+ *
+ * Registers 0x01, 0x02 are control registers and should not
+ * change on their own.
+ *
+ * Register 0x06 bits b6 and b7 are control bits, and should
+ * not change on their own.
+ *
+ * Register 0x07 bits b3 to b0 are control bits, and should
+ * not change on their own.
+ */
+
+ /* read register 0x02 reserved bit, expect 0 */
+ v = i2c_smbus_read_byte_data(client, LTC4245_CONTROL);
+ if (v < 0 || (v & 0x04) != 0)
+ return -ENODEV;
+
+ /* read register 0x07 reserved bits, expect 0 */
+ v = i2c_smbus_read_byte_data(client, LTC4245_ADCADR);
+ if (v < 0 || (v & 0xf0) != 0)
+ return -ENODEV;
+
+ /* check that the alert register appears at all locations */
+ if (ltc4245_check_control_reg(client, LTC4245_ALERT, 0xff))
+ return -ENODEV;
+
+ /* check that the control register appears at all locations */
+ if (ltc4245_check_control_reg(client, LTC4245_CONTROL, 0xff))
+ return -ENODEV;
+
+ /* check that register 0x06 bits b6 and b7 stay constant */
+ if (ltc4245_check_control_reg(client, LTC4245_GPIO, 0xc0))
+ return -ENODEV;
+
+ /* check that register 0x07 bits b3-b0 stay constant */
+ if (ltc4245_check_control_reg(client, LTC4245_ADCADR, 0x0f))
+ return -ENODEV;
+ }
+
+ strlcpy(info->type, "ltc4245", I2C_NAME_SIZE);
+ dev_info(&adapter->dev, "ltc4245 %s at address 0x%02x\n",
+ kind < 0 ? "probed" : "forced",
+ client->addr);
+
+ return 0;
+}
+
+static const struct i2c_device_id ltc4245_id[] = {
+ { "ltc4245", ltc4245 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ltc4245_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ltc4245_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "ltc4245",
+ },
+ .probe = ltc4245_probe,
+ .remove = ltc4245_remove,
+ .id_table = ltc4245_id,
+ .detect = ltc4245_detect,
+ .address_data = &addr_data,
+};
+
+static int __init ltc4245_init(void)
+{
+ return i2c_add_driver(&ltc4245_driver);
+}
+
+static void __exit ltc4245_exit(void)
+{
+ i2c_del_driver(&ltc4245_driver);
+}
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
+MODULE_DESCRIPTION("LTC4245 driver");
+MODULE_LICENSE("GPL");
+
+module_init(ltc4245_init);
+module_exit(ltc4245_exit);
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index 5fbfa34c110e..fb052fea3744 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -43,6 +43,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/acpi.h>
#include <asm/io.h>
static u8 devid;
@@ -1627,6 +1628,11 @@ static int __init pc87360_device_add(unsigned short address)
continue;
res.start = extra_isa[i];
res.end = extra_isa[i] + PC87360_EXTENT - 1;
+
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto exit_device_put;
+
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
printk(KERN_ERR "pc87360: Device resource[%d] "
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index 7265f22ae5cd..3a8a0f7a7736 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -32,6 +32,7 @@
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/ioport.h>
+#include <linux/acpi.h>
#include <asm/io.h>
static unsigned short force_id;
@@ -524,6 +525,10 @@ static int __init pc87427_device_add(unsigned short address)
};
int err;
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto exit;
+
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev) {
err = -ENOMEM;
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index a276806f3d53..aa2e8318f167 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -62,6 +62,7 @@
#include <linux/jiffies.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/acpi.h>
#include <asm/io.h>
@@ -727,6 +728,10 @@ static int __devinit sis5595_device_add(unsigned short address)
};
int err;
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto exit;
+
pdev = platform_device_alloc("sis5595", address);
if (!pdev) {
err = -ENOMEM;
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index eb03544c731c..6f6d52b4fb64 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -36,6 +36,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/mutex.h>
+#include <linux/acpi.h>
#include <asm/io.h>
static unsigned short force_id;
@@ -303,6 +304,10 @@ static int __init smsc47b397_device_add(unsigned short address)
};
int err;
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto exit;
+
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev) {
err = -ENOMEM;
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index d1b498548736..a92dbb97ee99 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -37,6 +37,7 @@
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/acpi.h>
#include <asm/io.h>
static unsigned short force_id;
@@ -705,6 +706,10 @@ static int __init smsc47m1_device_add(unsigned short address,
};
int err;
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto exit;
+
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev) {
err = -ENOMEM;
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index f1ee5e731968..a022aedcaacb 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -41,6 +41,7 @@
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/acpi.h>
#include <asm/io.h>
@@ -783,6 +784,10 @@ static int __devinit via686a_device_add(unsigned short address)
};
int err;
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto exit;
+
pdev = platform_device_alloc("via686a", address);
if (!pdev) {
err = -ENOMEM;
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index 12b43590fa53..b0ce37852281 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -32,6 +32,7 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/ioport.h>
+#include <linux/acpi.h>
#include <asm/io.h>
static int uch_config = -1;
@@ -1259,6 +1260,10 @@ static int __init vt1211_device_add(unsigned short address)
}
res.name = pdev->name;
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto EXIT;
+
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
printk(KERN_ERR DRVNAME ": Device resource addition failed "
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index 5bc57275cae8..9982b45fbb14 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -35,6 +35,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/acpi.h>
#include <asm/io.h>
static int force_addr;
@@ -894,6 +895,10 @@ static int __devinit vt8231_device_add(unsigned short address)
};
int err;
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto exit;
+
pdev = platform_device_alloc("vt8231", address);
if (!pdev) {
err = -ENOMEM;
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 075164dd65a7..cb808d015361 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -48,6 +48,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/acpi.h>
#include <asm/io.h>
#include "lm75.h"
@@ -502,7 +503,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
}
for (i = 0; i < 4; i++) {
- /* pwmcfg, tolarance mapped for i=0, i=1 to same reg */
+ /* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
if (i != 1) {
pwmcfg = w83627ehf_read_value(data,
W83627EHF_REG_PWM_ENABLE[i]);
@@ -1544,6 +1545,11 @@ static int __init sensors_w83627ehf_init(void)
res.start = address + IOREGION_OFFSET;
res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
res.flags = IORESOURCE_IO;
+
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto exit;
+
err = platform_device_add_resources(pdev, &res, 1);
if (err) {
printk(KERN_ERR DRVNAME ": Device resource addition failed "
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index b30e5796cb26..389150ba30d3 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -50,6 +50,7 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/ioport.h>
+#include <linux/acpi.h>
#include <asm/io.h>
#include "lm75.h"
@@ -1793,6 +1794,10 @@ static int __init w83627hf_device_add(unsigned short address,
};
int err;
+ err = acpi_check_resource_conflict(&res);
+ if (err)
+ goto exit;
+
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev) {
err = -ENOMEM;
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index fc12bd412e3a..dbfb30c588d8 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -58,7 +58,10 @@ static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
0x2e, 0x2f, I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD_4(w83781d, w83782d, w83783s, as99127f);
-I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
+
+static unsigned short force_subclients[4];
+module_param_array(force_subclients, short, NULL, 0);
+MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
static int reset;
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index 5768def8a4f2..97851c5ba3a3 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -53,7 +53,10 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(w83791d);
-I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
+
+static unsigned short force_subclients[4];
+module_param_array(force_subclients, short, NULL, 0);
+MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
static int reset;
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index cf94c5b0c879..2be16194ddf3 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -51,7 +51,10 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(w83792d);
-I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
+
+static unsigned short force_subclients[4];
+module_param_array(force_subclients, short, NULL, 0);
+MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
static int init;
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index 0a739f1c69be..47dd398f7258 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -42,7 +42,10 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f,
/* Insmod parameters */
I2C_CLIENT_INSMOD_1(w83793);
-I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
+
+static unsigned short force_subclients[4];
+module_param_array(force_subclients, short, NULL, 0);
+MODULE_PARM_DESC(force_subclients, "List of subclient addresses: "
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
static int reset;
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index fc3e5b026423..dd9e796fad69 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -399,8 +399,8 @@ static int __devinit ali1563_probe(struct pci_dev * dev,
if ((error = ali1563_setup(dev)))
goto exit;
ali1563_adapter.dev.parent = &dev->dev;
- sprintf(ali1563_adapter.name,"SMBus ALi 1563 Adapter @ %04x",
- ali1563_smba);
+ snprintf(ali1563_adapter.name, sizeof(ali1563_adapter.name),
+ "SMBus ALi 1563 Adapter @ %04x", ali1563_smba);
if ((error = i2c_add_adapter(&ali1563_adapter)))
goto exit_shutdown;
return 0;
diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c
index 8ba2bcf727d3..378fcb5d5783 100644
--- a/drivers/i2c/busses/i2c-amd756-s4882.c
+++ b/drivers/i2c/busses/i2c-amd756-s4882.c
@@ -197,8 +197,8 @@ static int __init amd756_s4882_init(void)
for (i = 1; i < 5; i++) {
s4882_algo[i] = *(amd756_smbus.algo);
s4882_adapter[i] = amd756_smbus;
- sprintf(s4882_adapter[i].name,
- "SMBus 8111 adapter (CPU%d)", i-1);
+ snprintf(s4882_adapter[i].name, sizeof(s4882_adapter[i].name),
+ "SMBus 8111 adapter (CPU%d)", i-1);
s4882_adapter[i].algo = s4882_algo+i;
s4882_adapter[i].dev.parent = amd756_smbus.dev.parent;
}
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 424dad6f18d8..36bee5b9c952 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -380,8 +380,9 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
/* set up the sysfs linkage to our parent device */
amd756_smbus.dev.parent = &pdev->dev;
- sprintf(amd756_smbus.name, "SMBus %s adapter at %04x",
- chipname[id->driver_data], amd756_ioport);
+ snprintf(amd756_smbus.name, sizeof(amd756_smbus.name),
+ "SMBus %s adapter at %04x", chipname[id->driver_data],
+ amd756_ioport);
error = i2c_add_adapter(&amd756_smbus);
if (error) {
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 9efb02137254..67d9dc5b351b 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -222,7 +222,7 @@ static int __devinit at91_i2c_probe(struct platform_device *pdev)
rc = -ENOMEM;
goto fail2;
}
- sprintf(adapter->name, "AT91");
+ snprintf(adapter->name, sizeof(adapter->name), "AT91");
adapter->algo = &at91_algorithm;
adapter->class = I2C_CLASS_HWMON;
adapter->dev.parent = &pdev->dev;
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 3c855ff2992f..3fd2c417c1e0 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -656,7 +656,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
p_adap->algo = &bfin_twi_algorithm;
p_adap->algo_data = iface;
- p_adap->class = I2C_CLASS_ALL;
+ p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
p_adap->dev.parent = &pdev->dev;
rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 5123eb69a971..526625eaa84b 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -64,7 +64,7 @@
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
-#include <asm/io.h>
+#include <linux/io.h>
/* I801 SMBus address offsets */
#define SMBHSTSTS (0 + i801_smba)
@@ -583,6 +583,40 @@ static struct pci_device_id i801_ids[] = {
MODULE_DEVICE_TABLE (pci, i801_ids);
+#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE
+static unsigned char apanel_addr;
+
+/* Scan the system ROM for the signature "FJKEYINF" */
+static __init const void __iomem *bios_signature(const void __iomem *bios)
+{
+ ssize_t offset;
+ const unsigned char signature[] = "FJKEYINF";
+
+ for (offset = 0; offset < 0x10000; offset += 0x10) {
+ if (check_signature(bios + offset, signature,
+ sizeof(signature)-1))
+ return bios + offset;
+ }
+ return NULL;
+}
+
+static void __init input_apanel_init(void)
+{
+ void __iomem *bios;
+ const void __iomem *p;
+
+ bios = ioremap(0xF0000, 0x10000); /* Can't fail */
+ p = bios_signature(bios);
+ if (p) {
+ /* just use the first address */
+ apanel_addr = readb(p + 8 + 3) >> 1;
+ }
+ iounmap(bios);
+}
+#else
+static void __init input_apanel_init(void) {}
+#endif
+
static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
unsigned char temp;
@@ -667,6 +701,19 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
dev_err(&dev->dev, "Failed to add SMBus adapter\n");
goto exit_release;
}
+
+ /* Register optional slaves */
+#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE
+ if (apanel_addr) {
+ struct i2c_board_info info;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = apanel_addr;
+ strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
+ i2c_new_device(&i801_adapter, &info);
+ }
+#endif
+
return 0;
exit_release:
@@ -717,6 +764,7 @@ static struct pci_driver i801_driver = {
static int __init i2c_i801_init(void)
{
+ input_apanel_init();
return pci_register_driver(&i801_driver);
}
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 587f5b2380d4..6af68146c342 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -1076,10 +1076,10 @@ static int i2c_pxa_probe(struct platform_device *dev)
#ifdef CONFIG_I2C_PXA_SLAVE
printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n",
- i2c->adap.dev.bus_id, i2c->slave_addr);
+ dev_name(&i2c->adap.dev), i2c->slave_addr);
#else
printk(KERN_INFO "I2C: %s: PXA I2C adapter\n",
- i2c->adap.dev.bus_id);
+ dev_name(&i2c->adap.dev));
#endif
return 0;
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index f69f91ffb469..5b7f95641ba4 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -906,7 +906,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, i2c);
- dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id);
+ dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
return 0;
err_cpufreq:
diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
index 5e0e254976de..baa28b73ae42 100644
--- a/drivers/i2c/busses/i2c-sh7760.c
+++ b/drivers/i2c/busses/i2c-sh7760.c
@@ -475,7 +475,7 @@ static int __devinit sh7760_i2c_probe(struct platform_device *pdev)
id->adap.nr = pdev->id;
id->adap.algo = &sh7760_i2c_algo;
- id->adap.class = I2C_CLASS_ALL;
+ id->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
id->adap.retries = 3;
id->adap.algo_data = id;
id->adap.dev.parent = &pdev->dev;
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 6c3d60b939bf..1c01083b01b5 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -500,7 +500,7 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
for (n = res->start; hook && n <= res->end; n++) {
if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED,
- dev->dev.bus_id, dev))
+ dev_name(&dev->dev), dev))
goto rollback;
}
k++;
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index dfc2d5eb6a68..8ce2daff985c 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -389,8 +389,8 @@ static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_
/* set up the sysfs linkage to our parent device */
sis5595_adapter.dev.parent = &dev->dev;
- sprintf(sis5595_adapter.name, "SMBus SIS5595 adapter at %04x",
- sis5595_base + SMB_INDEX);
+ snprintf(sis5595_adapter.name, sizeof(sis5595_adapter.name),
+ "SMBus SIS5595 adapter at %04x", sis5595_base + SMB_INDEX);
err = i2c_add_adapter(&sis5595_adapter);
if (err) {
release_region(sis5595_base + SMB_INDEX, 2);
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index e7c4b790da54..9c9c016ff2b5 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -487,8 +487,8 @@ static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_i
/* set up the sysfs linkage to our parent device */
sis630_adapter.dev.parent = &dev->dev;
- sprintf(sis630_adapter.name, "SMBus SIS630 adapter at %04x",
- acpi_base + SMB_STS);
+ snprintf(sis630_adapter.name, sizeof(sis630_adapter.name),
+ "SMBus SIS630 adapter at %04x", acpi_base + SMB_STS);
return i2c_add_adapter(&sis630_adapter);
}
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 864ac561fdbb..b9bef04b7be4 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -114,18 +114,6 @@ config SENSORS_PCF8591
These devices are hard to detect and rarely found on mainstream
hardware. If unsure, say N.
-config ISP1301_OMAP
- tristate "Philips ISP1301 with OMAP OTG"
- depends on ARCH_OMAP_OTG
- help
- If you say yes here you get support for the Philips ISP1301
- USB-On-The-Go transceiver working with the OMAP OTG controller.
- The ISP1301 is used in products including H2 and H3 development
- boards for Texas Instruments OMAP processors.
-
- This driver can also be built as a module. If so, the module
- will be called isp1301_omap.
-
config SENSORS_MAX6875
tristate "Maxim MAX6875 Power supply supervisor"
depends on EXPERIMENTAL
@@ -151,15 +139,4 @@ config SENSORS_TSL2550
This driver can also be built as a module. If so, the module
will be called tsl2550.
-config MCU_MPC8349EMITX
- tristate "MPC8349E-mITX MCU driver"
- depends on I2C && PPC_83xx
- select GENERIC_GPIO
- select ARCH_REQUIRE_GPIOLIB
- help
- Say Y here to enable soft power-off functionality on the Freescale
- boards with the MPC8349E-mITX-compatible MCU chips. This driver will
- also register MCU GPIOs with the generic GPIO API, so you'll able
- to use MCU pins as GPIOs.
-
endmenu
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index 8b95f41a5001..00fcb5193ac2 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -18,9 +18,7 @@ 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_SENSORS_TSL2550) += tsl2550.o
-obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/chips/mcu_mpc8349emitx.c b/drivers/i2c/chips/mcu_mpc8349emitx.c
deleted file mode 100644
index 82a9bcb858b6..000000000000
--- a/drivers/i2c/chips/mcu_mpc8349emitx.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Power Management and GPIO expander driver for MPC8349E-mITX-compatible MCU
- *
- * Copyright (c) 2008 MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.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.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/mutex.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-
-/*
- * I don't have specifications for the MCU firmware, I found this register
- * and bits positions by the trial&error method.
- */
-#define MCU_REG_CTRL 0x20
-#define MCU_CTRL_POFF 0x40
-
-#define MCU_NUM_GPIO 2
-
-struct mcu {
- struct mutex lock;
- struct device_node *np;
- struct i2c_client *client;
- struct of_gpio_chip of_gc;
- u8 reg_ctrl;
-};
-
-static struct mcu *glob_mcu;
-
-static void mcu_power_off(void)
-{
- struct mcu *mcu = glob_mcu;
-
- pr_info("Sending power-off request to the MCU...\n");
- mutex_lock(&mcu->lock);
- i2c_smbus_write_byte_data(glob_mcu->client, MCU_REG_CTRL,
- mcu->reg_ctrl | MCU_CTRL_POFF);
- mutex_unlock(&mcu->lock);
-}
-
-static void mcu_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
-{
- struct of_gpio_chip *of_gc = to_of_gpio_chip(gc);
- struct mcu *mcu = container_of(of_gc, struct mcu, of_gc);
- u8 bit = 1 << (4 + gpio);
-
- mutex_lock(&mcu->lock);
- if (val)
- mcu->reg_ctrl &= ~bit;
- else
- mcu->reg_ctrl |= bit;
-
- i2c_smbus_write_byte_data(mcu->client, MCU_REG_CTRL, mcu->reg_ctrl);
- mutex_unlock(&mcu->lock);
-}
-
-static int mcu_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
-{
- mcu_gpio_set(gc, gpio, val);
- return 0;
-}
-
-static int mcu_gpiochip_add(struct mcu *mcu)
-{
- struct device_node *np;
- struct of_gpio_chip *of_gc = &mcu->of_gc;
- struct gpio_chip *gc = &of_gc->gc;
- int ret;
-
- np = of_find_compatible_node(NULL, NULL, "fsl,mcu-mpc8349emitx");
- if (!np)
- return -ENODEV;
-
- gc->owner = THIS_MODULE;
- gc->label = np->full_name;
- gc->can_sleep = 1;
- gc->ngpio = MCU_NUM_GPIO;
- gc->base = -1;
- gc->set = mcu_gpio_set;
- gc->direction_output = mcu_gpio_dir_out;
- of_gc->gpio_cells = 2;
- of_gc->xlate = of_gpio_simple_xlate;
-
- np->data = of_gc;
- mcu->np = np;
-
- /*
- * We don't want to lose the node, its ->data and ->full_name...
- * So, if succeeded, we don't put the node here.
- */
- ret = gpiochip_add(gc);
- if (ret)
- of_node_put(np);
- return ret;
-}
-
-static int mcu_gpiochip_remove(struct mcu *mcu)
-{
- int ret;
-
- ret = gpiochip_remove(&mcu->of_gc.gc);
- if (ret)
- return ret;
- of_node_put(mcu->np);
-
- return 0;
-}
-
-static int __devinit mcu_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct mcu *mcu;
- int ret;
-
- mcu = kzalloc(sizeof(*mcu), GFP_KERNEL);
- if (!mcu)
- return -ENOMEM;
-
- mutex_init(&mcu->lock);
- mcu->client = client;
- i2c_set_clientdata(client, mcu);
-
- ret = i2c_smbus_read_byte_data(mcu->client, MCU_REG_CTRL);
- if (ret < 0)
- goto err;
- mcu->reg_ctrl = ret;
-
- ret = mcu_gpiochip_add(mcu);
- if (ret)
- goto err;
-
- /* XXX: this is potentially racy, but there is no lock for ppc_md */
- if (!ppc_md.power_off) {
- glob_mcu = mcu;
- ppc_md.power_off = mcu_power_off;
- dev_info(&client->dev, "will provide power-off service\n");
- }
-
- return 0;
-err:
- kfree(mcu);
- return ret;
-}
-
-static int __devexit mcu_remove(struct i2c_client *client)
-{
- struct mcu *mcu = i2c_get_clientdata(client);
- int ret;
-
- if (glob_mcu == mcu) {
- ppc_md.power_off = NULL;
- glob_mcu = NULL;
- }
-
- ret = mcu_gpiochip_remove(mcu);
- if (ret)
- return ret;
- i2c_set_clientdata(client, NULL);
- kfree(mcu);
- return 0;
-}
-
-static const struct i2c_device_id mcu_ids[] = {
- { "mcu-mpc8349emitx", },
- {},
-};
-MODULE_DEVICE_TABLE(i2c, mcu_ids);
-
-static struct i2c_driver mcu_driver = {
- .driver = {
- .name = "mcu-mpc8349emitx",
- .owner = THIS_MODULE,
- },
- .probe = mcu_probe,
- .remove = __devexit_p(mcu_remove),
- .id_table = mcu_ids,
-};
-
-static int __init mcu_init(void)
-{
- return i2c_add_driver(&mcu_driver);
-}
-module_init(mcu_init);
-
-static void __exit mcu_exit(void)
-{
- i2c_del_driver(&mcu_driver);
-}
-module_exit(mcu_exit);
-
-MODULE_DESCRIPTION("Power Management and GPIO expander driver for "
- "MPC8349E-mITX-compatible MCU");
-MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index c6a63f46bc15..b1c9abe24c7b 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -459,7 +459,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
pr_debug("I2C adapter driver [%s] forgot to specify "
"physical device\n", adap->name);
}
- sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
+ dev_set_name(&adap->dev, "i2c-%d", adap->nr);
adap->dev.release = &i2c_adapter_dev_release;
adap->dev.class = &i2c_adapter_class;
res = device_register(&adap->dev);
@@ -845,8 +845,8 @@ int i2c_attach_client(struct i2c_client *client)
} else
client->dev.release = i2c_client_dev_release;
- snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
- "%d-%04x", i2c_adapter_id(adapter), client->addr);
+ dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adapter),
+ client->addr);
res = device_register(&client->dev);
if (res)
goto out_err;
@@ -856,7 +856,7 @@ int i2c_attach_client(struct i2c_client *client)
mutex_unlock(&adapter->clist_lock);
dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
- client->name, client->dev.bus_id);
+ client->name, dev_name(&client->dev));
if (adapter->client_register) {
if (adapter->client_register(client)) {
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 3f9503867e6b..b1c6f68d98ce 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -701,11 +701,6 @@ config BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
depends on SOC_AU1200 && BLK_DEV_IDE_AU1XXX
endchoice
-config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ
- int "Maximum transfer size (KB) per request (up to 128)"
- default "128"
- depends on BLK_DEV_IDE_AU1XXX
-
config BLK_DEV_IDE_TX4938
tristate "TX4938 internal IDE support"
depends on SOC_TX4938
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index 2f9e941968d6..d8f295bdad76 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -18,12 +18,6 @@
#include <linux/dmi.h>
#include <acpi/acpi_bus.h>
-#include <acpi/acnames.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acparser.h>
-#include <acpi/acexcep.h>
-#include <acpi/acmacros.h>
-#include <acpi/actypes.h>
#define REGS_PER_GTF 7
struct taskfile_array {
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 4088a622873e..806760d24cef 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -633,7 +633,7 @@ static void ide_disk_setup(ide_drive_t *drive)
printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name,
q->max_sectors / 2);
- if (ata_id_is_ssd(id) || ata_id_is_cfa(id))
+ if (ata_id_is_ssd(id))
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
/* calculate drive capacity, and select LBA if possible */
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index e728cfe7273f..753b92ebe0ae 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -493,7 +493,7 @@ static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long ti
stat = tp_ops->read_status(hwif);
if (stat & ATA_BUSY) {
- local_irq_save(flags);
+ local_save_flags(flags);
local_irq_enable_in_hardirq();
timeout += jiffies;
while ((stat = tp_ops->read_status(hwif)) & ATA_BUSY) {
diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c
index 4b3bf6a06b70..60538d9c84ee 100644
--- a/drivers/ide/ide-pm.c
+++ b/drivers/ide/ide-pm.c
@@ -186,12 +186,10 @@ void ide_complete_pm_request(ide_drive_t *drive, struct request *rq)
blk_pm_suspend_request(rq) ? "suspend" : "resume");
#endif
spin_lock_irqsave(q->queue_lock, flags);
- if (blk_pm_suspend_request(rq)) {
+ if (blk_pm_suspend_request(rq))
blk_stop_queue(q);
- } else {
+ else
drive->dev_flags &= ~IDE_DFLAG_BLOCKED;
- blk_start_queue(q);
- }
spin_unlock_irqrestore(q->queue_lock, flags);
drive->hwif->rq = NULL;
@@ -219,6 +217,8 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
* point.
*/
ide_hwif_t *hwif = drive->hwif;
+ struct request_queue *q = drive->queue;
+ unsigned long flags;
int rc;
#ifdef DEBUG_PM
printk("%s: Wakeup request inited, waiting for !BSY...\n", drive->name);
@@ -231,5 +231,9 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
rc = ide_wait_not_busy(hwif, 100000);
if (rc)
printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ blk_start_queue(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
}
}
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 0ccbb4459fb9..312127ea443a 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -796,7 +796,7 @@ static int ide_probe_port(ide_hwif_t *hwif)
if (irqd)
disable_irq(hwif->irq);
- local_irq_save(flags);
+ local_save_flags(flags);
local_irq_enable_in_hardirq();
if (ide_port_wait_ready(hwif) == -EBUSY)
diff --git a/drivers/ide/it821x.c b/drivers/ide/it821x.c
index 0be27ac1f077..e1c4f5437396 100644
--- a/drivers/ide/it821x.c
+++ b/drivers/ide/it821x.c
@@ -68,6 +68,8 @@
#define DRV_NAME "it821x"
+#define QUIRK_VORTEX86 1
+
struct it821x_dev
{
unsigned int smart:1, /* Are we in smart raid mode */
@@ -79,6 +81,7 @@ struct it821x_dev
u16 pio[2]; /* Cached PIO values */
u16 mwdma[2]; /* Cached MWDMA values */
u16 udma[2]; /* Cached UDMA values (per drive) */
+ u16 quirks;
};
#define ATA_66 0
@@ -557,8 +560,7 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
* this is necessary.
*/
- pci_read_config_byte(dev, 0x08, &conf);
- if (conf == 0x10) {
+ if (dev->revision == 0x10) {
idev->timing10 = 1;
hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA;
if (idev->smart == 0)
@@ -577,6 +579,12 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
hwif->ultra_mask = ATA_UDMA6;
hwif->mwdma_mask = ATA_MWDMA2;
+
+ /* Vortex86SX quirk: prevent Ultra-DMA mode to fix BadCRC issue */
+ if (idev->quirks & QUIRK_VORTEX86) {
+ if (dev->revision == 0x11)
+ hwif->ultra_mask = 0;
+ }
}
static void it8212_disable_raid(struct pci_dev *dev)
@@ -649,6 +657,8 @@ static int __devinit it821x_init_one(struct pci_dev *dev, const struct pci_devic
return -ENOMEM;
}
+ itdevs->quirks = id->driver_data;
+
rc = ide_pci_init_one(dev, &it821x_chipset, itdevs);
if (rc)
kfree(itdevs);
@@ -668,6 +678,7 @@ static void __devexit it821x_remove(struct pci_dev *dev)
static const struct pci_device_id it821x_pci_tbl[] = {
{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), 0 },
{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), 0 },
+ { PCI_VDEVICE(RDC, PCI_DEVICE_ID_RDC_D1010), QUIRK_VORTEX86 },
{ 0, },
};
diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
index 48cc748c5043..6297956507c0 100644
--- a/drivers/ide/sl82c105.c
+++ b/drivers/ide/sl82c105.c
@@ -310,10 +310,6 @@ static const struct ide_port_info sl82c105_chipset __devinitdata = {
.dma_ops = &sl82c105_dma_ops,
.host_flags = IDE_HFLAG_IO_32BIT |
IDE_HFLAG_UNMASK_IRQS |
-/* FIXME: check for Compatibility mode in generic IDE PCI code */
-#if defined(CONFIG_LOPEC) || defined(CONFIG_SANDPOINT)
- IDE_HFLAG_FORCE_LEGACY_IRQS |
-#endif
IDE_HFLAG_SERIALIZE_DMA |
IDE_HFLAG_NO_AUTODMA,
.pio_mask = ATA_PIO5,
diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c
index b4ef218072cd..d9095345f7ca 100644
--- a/drivers/ide/tx4938ide.c
+++ b/drivers/ide/tx4938ide.c
@@ -202,7 +202,6 @@ static const struct ide_tp_ops tx4938ide_tp_ops = {
.exec_command = ide_exec_command,
.read_status = ide_read_status,
.read_altstatus = ide_read_altstatus,
- .read_sff_dma_status = ide_read_sff_dma_status,
.set_irq = ide_set_irq,
diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
index fecc0e03c3fc..703c3eeb20a8 100644
--- a/drivers/ide/via82cxxx.c
+++ b/drivers/ide/via82cxxx.c
@@ -432,8 +432,6 @@ static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_i
if (via_clock < 20000 || via_clock > 50000) {
printk(KERN_WARNING DRV_NAME ": User given PCI clock speed "
"impossible (%d), using 33 MHz instead.\n", via_clock);
- printk(KERN_WARNING DRV_NAME ": Use ide0=ata66 if you want "
- "to assume 80-wire cable.\n");
via_clock = 33333;
}
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
index c90be4070e40..31400c8ae051 100644
--- a/drivers/ieee1394/csr.c
+++ b/drivers/ieee1394/csr.c
@@ -68,22 +68,22 @@ static struct hpsb_highlevel csr_highlevel = {
.host_reset = host_reset,
};
-static struct hpsb_address_ops map_ops = {
+const static struct hpsb_address_ops map_ops = {
.read = read_maps,
};
-static struct hpsb_address_ops fcp_ops = {
+const static struct hpsb_address_ops fcp_ops = {
.write = write_fcp,
};
-static struct hpsb_address_ops reg_ops = {
+const static struct hpsb_address_ops reg_ops = {
.read = read_regs,
.write = write_regs,
.lock = lock_regs,
.lock64 = lock64_regs,
};
-static struct hpsb_address_ops config_rom_ops = {
+const static struct hpsb_address_ops config_rom_ops = {
.read = read_config_rom,
};
@@ -217,7 +217,7 @@ static void add_host(struct hpsb_host *host)
host->csr.generation = 2;
- bus_info[1] = __constant_cpu_to_be32(0x31333934);
+ bus_info[1] = IEEE1394_BUSID_MAGIC;
bus_info[2] = cpu_to_be32((hpsb_disable_irm ? 0 : 1 << CSR_IRMC_SHIFT) |
(1 << CSR_CMC_SHIFT) |
(1 << CSR_ISC_SHIFT) |
@@ -250,7 +250,7 @@ static void remove_host(struct hpsb_host *host)
{
quadlet_t bus_info[CSR_BUS_INFO_SIZE];
- bus_info[1] = __constant_cpu_to_be32(0x31333934);
+ bus_info[1] = IEEE1394_BUSID_MAGIC;
bus_info[2] = cpu_to_be32((0 << CSR_IRMC_SHIFT) |
(0 << CSR_CMC_SHIFT) |
(0 << CSR_ISC_SHIFT) |
diff --git a/drivers/ieee1394/csr.h b/drivers/ieee1394/csr.h
index f11546550d84..90fb3f2192c3 100644
--- a/drivers/ieee1394/csr.h
+++ b/drivers/ieee1394/csr.h
@@ -50,11 +50,11 @@
#define CSR_MAX_ROM_SHIFT 8
#define CSR_GENERATION_SHIFT 4
-#define CSR_SET_BUS_INFO_GENERATION(csr, gen) \
- ((csr)->bus_info_data[2] = \
- cpu_to_be32((be32_to_cpu((csr)->bus_info_data[2]) & \
- ~(0xf << CSR_GENERATION_SHIFT)) | \
- (gen) << CSR_GENERATION_SHIFT))
+static inline void csr_set_bus_info_generation(struct csr1212_csr *csr, u8 gen)
+{
+ csr->bus_info_data[2] &= ~cpu_to_be32(0xf << CSR_GENERATION_SHIFT);
+ csr->bus_info_data[2] |= cpu_to_be32((u32)gen << CSR_GENERATION_SHIFT);
+}
struct csr_control {
spinlock_t lock;
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
index 5e38a68b8af2..a6dfeb0b3372 100644
--- a/drivers/ieee1394/csr1212.c
+++ b/drivers/ieee1394/csr1212.c
@@ -1077,15 +1077,10 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
int i;
int ret;
- /* IEEE 1212 says that the entire bus info block should be readable in
- * a single transaction regardless of the max_rom value.
- * Unfortunately, many IEEE 1394 devices do not abide by that, so the
- * bus info block will be read 1 quadlet at a time. The rest of the
- * ConfigROM will be read according to the max_rom field. */
for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) {
ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
- sizeof(u32), &csr->cache_head->data[bytes_to_quads(i)],
- csr->private);
+ &csr->cache_head->data[bytes_to_quads(i)],
+ csr->private);
if (ret != CSR1212_SUCCESS)
return ret;
@@ -1104,8 +1099,8 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
* a time. */
for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) {
ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
- sizeof(u32), &csr->cache_head->data[bytes_to_quads(i)],
- csr->private);
+ &csr->cache_head->data[bytes_to_quads(i)],
+ csr->private);
if (ret != CSR1212_SUCCESS)
return ret;
}
@@ -1289,7 +1284,7 @@ csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
if (csr->ops->bus_read(csr,
CSR1212_REGISTER_SPACE_BASE + kv->offset,
- sizeof(u32), &q, csr->private))
+ &q, csr->private))
return -EIO;
kv->value.leaf.len = be32_to_cpu(q) >> 16;
@@ -1372,17 +1367,8 @@ csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
addr = (CSR1212_CSR_ARCH_REG_SPACE_BASE + cache->offset +
cr->offset_end) & ~(csr->max_rom - 1);
- if (csr->ops->bus_read(csr, addr, csr->max_rom, cache_ptr,
- csr->private)) {
- if (csr->max_rom == 4)
- /* We've got problems! */
- return -EIO;
-
- /* Apperently the max_rom value was a lie, set it to
- * do quadlet reads and try again. */
- csr->max_rom = 4;
- continue;
- }
+ if (csr->ops->bus_read(csr, addr, cache_ptr, csr->private))
+ return -EIO;
cr->offset_end += csr->max_rom - (cr->offset_end &
(csr->max_rom - 1));
@@ -1433,7 +1419,6 @@ csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
int csr1212_parse_csr(struct csr1212_csr *csr)
{
- static const int mr_map[] = { 4, 64, 1024, 0 };
struct csr1212_dentry *dentry;
int ret;
@@ -1443,15 +1428,13 @@ int csr1212_parse_csr(struct csr1212_csr *csr)
if (ret != CSR1212_SUCCESS)
return ret;
- if (!csr->ops->get_max_rom) {
- csr->max_rom = mr_map[0]; /* default value */
- } else {
- int i = csr->ops->get_max_rom(csr->bus_info_data,
- csr->private);
- if (i & ~0x3)
- return -EINVAL;
- csr->max_rom = mr_map[i];
- }
+ /*
+ * There has been a buggy firmware with bus_info_block.max_rom > 0
+ * spotted which actually only supported quadlet read requests to the
+ * config ROM. Therefore read everything quadlet by quadlet regardless
+ * of what the bus info block says.
+ */
+ csr->max_rom = 4;
csr->cache_head->layout_head = csr->root_kv;
csr->cache_head->layout_tail = csr->root_kv;
diff --git a/drivers/ieee1394/csr1212.h b/drivers/ieee1394/csr1212.h
index 043039fc63ec..a892d922dbc9 100644
--- a/drivers/ieee1394/csr1212.h
+++ b/drivers/ieee1394/csr1212.h
@@ -181,7 +181,7 @@ struct csr1212_csr_rom_cache {
struct csr1212_csr {
size_t bus_info_len; /* bus info block length in bytes */
size_t crc_len; /* crc length in bytes */
- u32 *bus_info_data; /* bus info data incl bus name and EUI */
+ __be32 *bus_info_data; /* bus info data incl bus name and EUI */
void *private; /* private, bus specific data */
struct csr1212_bus_ops *ops;
@@ -200,7 +200,7 @@ struct csr1212_bus_ops {
* entries located in the Units Space. Must return 0 on success
* anything else indicates an error. */
int (*bus_read) (struct csr1212_csr *csr, u64 addr,
- u16 length, void *buffer, void *private);
+ void *buffer, void *private);
/* This function is used by csr1212 to allocate a region in units space
* in the event that Config ROM entries don't all fit in the predefined
@@ -211,11 +211,6 @@ struct csr1212_bus_ops {
/* This function is used by csr1212 to release a region in units space
* that is no longer needed. */
void (*release_addr) (u64 addr, void *private);
-
- /* This function is used by csr1212 to determine the max read request
- * supported by a remote node when reading the ConfigROM space. Must
- * return 0, 1, or 2 per IEEE 1212. */
- int (*get_max_rom) (u32 *bus_info, void *private);
};
diff --git a/drivers/ieee1394/dv1394-private.h b/drivers/ieee1394/dv1394-private.h
index 7d1d2845b420..18b92cbf4a9f 100644
--- a/drivers/ieee1394/dv1394-private.h
+++ b/drivers/ieee1394/dv1394-private.h
@@ -77,11 +77,11 @@ static inline void fill_cip_header(struct CIP_header *cip,
See the Texas Instruments OHCI 1394 chipset documentation.
*/
-struct output_more_immediate { u32 q[8]; };
-struct output_more { u32 q[4]; };
-struct output_last { u32 q[4]; };
-struct input_more { u32 q[4]; };
-struct input_last { u32 q[4]; };
+struct output_more_immediate { __le32 q[8]; };
+struct output_more { __le32 q[4]; };
+struct output_last { __le32 q[4]; };
+struct input_more { __le32 q[4]; };
+struct input_last { __le32 q[4]; };
/* outputs */
@@ -92,9 +92,9 @@ static inline void fill_output_more_immediate(struct output_more_immediate *omi,
unsigned int payload_size)
{
omi->q[0] = cpu_to_le32(0x02000000 | 8); /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */
- omi->q[1] = 0;
- omi->q[2] = 0;
- omi->q[3] = 0;
+ omi->q[1] = cpu_to_le32(0);
+ omi->q[2] = cpu_to_le32(0);
+ omi->q[3] = cpu_to_le32(0);
/* IT packet header */
omi->q[4] = cpu_to_le32( (0x0 << 16) /* IEEE1394_SPEED_100 */
@@ -106,8 +106,8 @@ static inline void fill_output_more_immediate(struct output_more_immediate *omi,
/* reserved field; mimic behavior of my Sony DSR-40 */
omi->q[5] = cpu_to_le32((payload_size << 16) | (0x7F << 8) | 0xA0);
- omi->q[6] = 0;
- omi->q[7] = 0;
+ omi->q[6] = cpu_to_le32(0);
+ omi->q[7] = cpu_to_le32(0);
}
static inline void fill_output_more(struct output_more *om,
@@ -116,8 +116,8 @@ static inline void fill_output_more(struct output_more *om,
{
om->q[0] = cpu_to_le32(data_size);
om->q[1] = cpu_to_le32(data_phys_addr);
- om->q[2] = 0;
- om->q[3] = 0;
+ om->q[2] = cpu_to_le32(0);
+ om->q[3] = cpu_to_le32(0);
}
static inline void fill_output_last(struct output_last *ol,
@@ -140,8 +140,8 @@ static inline void fill_output_last(struct output_last *ol,
ol->q[0] = cpu_to_le32(temp);
ol->q[1] = cpu_to_le32(data_phys_addr);
- ol->q[2] = 0;
- ol->q[3] = 0;
+ ol->q[2] = cpu_to_le32(0);
+ ol->q[3] = cpu_to_le32(0);
}
/* inputs */
@@ -161,8 +161,8 @@ static inline void fill_input_more(struct input_more *im,
im->q[0] = cpu_to_le32(temp);
im->q[1] = cpu_to_le32(data_phys_addr);
- im->q[2] = 0; /* branchAddress and Z not use in packet-per-buffer mode */
- im->q[3] = 0; /* xferStatus & resCount, resCount must be initialize to data_size */
+ im->q[2] = cpu_to_le32(0); /* branchAddress and Z not use in packet-per-buffer mode */
+ im->q[3] = cpu_to_le32(0); /* xferStatus & resCount, resCount must be initialize to data_size */
}
static inline void fill_input_last(struct input_last *il,
@@ -331,7 +331,7 @@ struct frame {
/* points to status/timestamp field of first DMA packet */
/* (we'll check it later to monitor timestamp accuracy) */
- u32 *frame_begin_timestamp;
+ __le32 *frame_begin_timestamp;
/* the timestamp we assigned to the first packet in the frame */
u32 assigned_timestamp;
@@ -348,15 +348,15 @@ struct frame {
that can cause interrupts. We'll check these from the
interrupt handler.
*/
- u32 *mid_frame_timestamp;
- u32 *frame_end_timestamp;
+ __le32 *mid_frame_timestamp;
+ __le32 *frame_end_timestamp;
/* branch address field of final packet. This is effectively
the "tail" in the chain of DMA descriptor blocks.
We will fill it with the address of the first DMA descriptor
block in the subsequent frame, once it is ready.
*/
- u32 *frame_end_branch;
+ __le32 *frame_end_branch;
/* the number of descriptors in the first descriptor block
of the frame. Needed to start DMA */
@@ -365,10 +365,10 @@ struct frame {
struct packet {
- u16 timestamp;
+ __le16 timestamp;
u16 invalid;
u16 iso_header;
- u16 data_length;
+ __le16 data_length;
u32 cip_h1;
u32 cip_h2;
unsigned char data[480];
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index c19f23267157..a329e6bd5d2d 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -265,7 +265,7 @@ static void frame_prepare(struct video_card *video, unsigned int this_frame)
/* these flags denote packets that need special attention */
int empty_packet, first_packet, last_packet, mid_packet;
- u32 *branch_address, *last_branch_address = NULL;
+ __le32 *branch_address, *last_branch_address = NULL;
unsigned long data_p;
int first_packet_empty = 0;
u32 cycleTimer, ct_sec, ct_cyc, ct_off;
@@ -848,7 +848,7 @@ static void receive_packets(struct video_card *video)
dma_addr_t block_dma = 0;
struct packet *data = NULL;
dma_addr_t data_dma = 0;
- u32 *last_branch_address = NULL;
+ __le32 *last_branch_address = NULL;
unsigned long irq_flags;
int want_interrupt = 0;
struct frame *f = NULL;
@@ -2110,17 +2110,17 @@ static void ir_tasklet_func(unsigned long data)
f = video->frames[next_i / MAX_PACKETS];
next = &(f->descriptor_pool[next_i % MAX_PACKETS]);
next_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma;
- next->u.in.il.q[0] |= 3 << 20; /* enable interrupt */
- next->u.in.il.q[2] = 0; /* disable branch */
+ next->u.in.il.q[0] |= cpu_to_le32(3 << 20); /* enable interrupt */
+ next->u.in.il.q[2] = cpu_to_le32(0); /* disable branch */
/* link previous to next */
prev_i = (next_i == 0) ? (MAX_PACKETS * video->n_frames - 1) : (next_i - 1);
f = video->frames[prev_i / MAX_PACKETS];
prev = &(f->descriptor_pool[prev_i % MAX_PACKETS]);
if (prev_i % (MAX_PACKETS/2)) {
- prev->u.in.il.q[0] &= ~(3 << 20); /* no interrupt */
+ prev->u.in.il.q[0] &= ~cpu_to_le32(3 << 20); /* no interrupt */
} else {
- prev->u.in.il.q[0] |= 3 << 20; /* enable interrupt */
+ prev->u.in.il.q[0] |= cpu_to_le32(3 << 20); /* enable interrupt */
}
prev->u.in.il.q[2] = cpu_to_le32(next_dma | 1); /* set Z=1 */
wmb();
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 20128692b339..1a919df809f8 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -92,7 +92,7 @@ struct partial_datagram {
struct list_head list;
u16 dgl;
u16 dg_size;
- u16 ether_type;
+ __be16 ether_type;
struct sk_buff *skb;
char *pbuf;
struct list_head frag_info;
@@ -181,7 +181,7 @@ static void ether1394_remove_host(struct hpsb_host *host);
static void ether1394_host_reset(struct hpsb_host *host);
/* Function for incoming 1394 packets */
-static struct hpsb_address_ops addr_ops = {
+const static struct hpsb_address_ops addr_ops = {
.write = ether1394_write,
};
@@ -245,12 +245,6 @@ static int ether1394_stop(struct net_device *dev)
return 0;
}
-/* Return statistics to the caller */
-static struct net_device_stats *ether1394_stats(struct net_device *dev)
-{
- return &(((struct eth1394_priv *)netdev_priv(dev))->stats);
-}
-
/* FIXME: What to do if we timeout? I think a host reset is probably in order,
* so that's what we do. Should we increment the stat counters too? */
static void ether1394_tx_timeout(struct net_device *dev)
@@ -516,16 +510,19 @@ static const struct header_ops ether1394_header_ops = {
.parse = ether1394_header_parse,
};
+static const struct net_device_ops ether1394_netdev_ops = {
+ .ndo_open = ether1394_open,
+ .ndo_stop = ether1394_stop,
+ .ndo_start_xmit = ether1394_tx,
+ .ndo_tx_timeout = ether1394_tx_timeout,
+ .ndo_change_mtu = ether1394_change_mtu,
+};
+
static void ether1394_init_dev(struct net_device *dev)
{
- dev->open = ether1394_open;
- dev->stop = ether1394_stop;
- dev->hard_start_xmit = ether1394_tx;
- dev->get_stats = ether1394_stats;
- dev->tx_timeout = ether1394_tx_timeout;
- dev->change_mtu = ether1394_change_mtu;
dev->header_ops = &ether1394_header_ops;
+ dev->netdev_ops = &ether1394_netdev_ops;
SET_ETHTOOL_OPS(dev, &ethtool_ops);
@@ -767,7 +764,7 @@ static int ether1394_header_parse(const struct sk_buff *skb,
static int ether1394_header_cache(const struct neighbour *neigh,
struct hh_cache *hh)
{
- unsigned short type = hh->hh_type;
+ __be16 type = hh->hh_type;
struct net_device *dev = neigh->dev;
struct eth1394hdr *eth =
(struct eth1394hdr *)((u8 *)hh->hh_data + 16 - ETH1394_HLEN);
@@ -795,7 +792,7 @@ static void ether1394_header_cache_update(struct hh_cache *hh,
******************************************/
/* Copied from net/ethernet/eth.c */
-static u16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev)
+static __be16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct eth1394hdr *eth;
unsigned char *rawp;
@@ -829,17 +826,17 @@ static u16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev)
/* Parse an encapsulated IP1394 header into an ethernet frame packet.
* We also perform ARP translation here, if need be. */
-static u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
+static __be16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
nodeid_t srcid, nodeid_t destid,
- u16 ether_type)
+ __be16 ether_type)
{
struct eth1394_priv *priv = netdev_priv(dev);
- u64 dest_hw;
- unsigned short ret = 0;
+ __be64 dest_hw;
+ __be16 ret = 0;
/* Setup our hw addresses. We use these to build the ethernet header. */
if (destid == (LOCAL_BUS | ALL_NODES))
- dest_hw = ~0ULL; /* broadcast */
+ dest_hw = ~cpu_to_be64(0); /* broadcast */
else
dest_hw = cpu_to_be64((u64)priv->host->csr.guid_hi << 32 |
priv->host->csr.guid_lo);
@@ -873,7 +870,7 @@ static u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
node = eth1394_find_node_guid(&priv->ip_node_list,
be64_to_cpu(guid));
if (!node)
- return 0;
+ return cpu_to_be16(0);
node_info =
(struct eth1394_node_info *)node->ud->device.driver_data;
@@ -1063,7 +1060,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
unsigned long flags;
struct eth1394_priv *priv = netdev_priv(dev);
union eth1394_hdr *hdr = (union eth1394_hdr *)buf;
- u16 ether_type = 0; /* initialized to clear warning */
+ __be16 ether_type = cpu_to_be16(0); /* initialized to clear warning */
int hdr_len;
struct unit_directory *ud = priv->ud_list[NODEID_TO_NODE(srcid)];
struct eth1394_node_info *node_info;
@@ -1075,7 +1072,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid "
"lookup failure: " NODE_BUS_FMT,
NODE_BUS_ARGS(priv->host, srcid));
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return -1;
}
ud = node->ud;
@@ -1098,7 +1095,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
skb = dev_alloc_skb(len + dev->hard_header_len + 15);
if (unlikely(!skb)) {
ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return -1;
}
skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
@@ -1217,15 +1214,15 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
spin_lock_irqsave(&priv->lock, flags);
if (!skb->protocol) {
- priv->stats.rx_errors++;
- priv->stats.rx_dropped++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_dropped++;
dev_kfree_skb_any(skb);
} else if (netif_rx(skb) == NET_RX_DROP) {
- priv->stats.rx_errors++;
- priv->stats.rx_dropped++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_dropped++;
} else {
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1234,8 +1231,6 @@ bad_proto:
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
- dev->last_rx = jiffies;
-
return 0;
}
@@ -1259,7 +1254,7 @@ static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
static void ether1394_iso(struct hpsb_iso *iso)
{
- quadlet_t *data;
+ __be32 *data;
char *buf;
struct eth1394_host_info *hi;
struct net_device *dev;
@@ -1283,7 +1278,7 @@ static void ether1394_iso(struct hpsb_iso *iso)
for (i = 0; i < nready; i++) {
struct hpsb_iso_packet_info *info =
&iso->infos[(iso->first_packet + i) % iso->buf_packets];
- data = (quadlet_t *)(iso->data_buf.kvirt + info->offset);
+ data = (__be32 *)(iso->data_buf.kvirt + info->offset);
/* skip over GASP header */
buf = (char *)data + 8;
@@ -1509,17 +1504,18 @@ static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len)
static void ether1394_dg_complete(struct packet_task *ptask, int fail)
{
struct sk_buff *skb = ptask->skb;
- struct eth1394_priv *priv = netdev_priv(skb->dev);
+ struct net_device *dev = skb->dev;
+ struct eth1394_priv *priv = netdev_priv(dev);
unsigned long flags;
/* Statistics */
spin_lock_irqsave(&priv->lock, flags);
if (fail) {
- priv->stats.tx_dropped++;
- priv->stats.tx_errors++;
+ dev->stats.tx_dropped++;
+ dev->stats.tx_errors++;
} else {
- priv->stats.tx_bytes += skb->len;
- priv->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1614,7 +1610,7 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev)
if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
priv->bc_dgl++;
} else {
- __be64 guid = get_unaligned((u64 *)hdr_buf.h_dest);
+ __be64 guid = get_unaligned((__be64 *)hdr_buf.h_dest);
node = eth1394_find_node_guid(&priv->ip_node_list,
be64_to_cpu(guid));
@@ -1696,8 +1692,8 @@ fail:
dev_kfree_skb(skb);
spin_lock_irqsave(&priv->lock, flags);
- priv->stats.tx_dropped++;
- priv->stats.tx_errors++;
+ dev->stats.tx_dropped++;
+ dev->stats.tx_errors++;
spin_unlock_irqrestore(&priv->lock, flags);
/*
diff --git a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h
index 4f3e2dd46f00..d53bac47b86f 100644
--- a/drivers/ieee1394/eth1394.h
+++ b/drivers/ieee1394/eth1394.h
@@ -54,7 +54,6 @@ enum eth1394_bc_states { ETHER1394_BC_ERROR,
/* Private structure for our ethernet driver */
struct eth1394_priv {
- struct net_device_stats stats; /* Device stats */
struct hpsb_host *host; /* The card for this dev */
u16 bc_maxpayload; /* Max broadcast payload */
u8 bc_sspd; /* Max broadcast speed */
@@ -82,7 +81,7 @@ struct eth1394_priv {
struct eth1394hdr {
unsigned char h_dest[ETH1394_ALEN]; /* destination eth1394 addr */
- unsigned short h_proto; /* packet type ID field */
+ __be16 h_proto; /* packet type ID field */
} __attribute__((packed));
static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb)
@@ -99,13 +98,13 @@ typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
struct eth1394_uf_hdr {
u16 lf:2;
u16 res:14;
- u16 ether_type; /* Ethernet packet type */
+ __be16 ether_type; /* Ethernet packet type */
} __attribute__((packed));
#elif defined __LITTLE_ENDIAN_BITFIELD
struct eth1394_uf_hdr {
u16 res:14;
u16 lf:2;
- u16 ether_type;
+ __be16 ether_type;
} __attribute__((packed));
#else
#error Unknown bit field type
@@ -117,7 +116,7 @@ struct eth1394_ff_hdr {
u16 lf:2;
u16 res1:2;
u16 dg_size:12; /* Datagram size */
- u16 ether_type; /* Ethernet packet type */
+ __be16 ether_type; /* Ethernet packet type */
u16 dgl; /* Datagram label */
u16 res2;
} __attribute__((packed));
@@ -126,7 +125,7 @@ struct eth1394_ff_hdr {
u16 dg_size:12;
u16 res1:2;
u16 lf:2;
- u16 ether_type;
+ __be16 ether_type;
u16 dgl;
u16 res2;
} __attribute__((packed));
@@ -207,11 +206,11 @@ struct eth1394_arp {
u16 opcode; /* ARP Opcode */
/* Above is exactly the same format as struct arphdr */
- u64 s_uniq_id; /* Sender's 64bit EUI */
+ __be64 s_uniq_id; /* Sender's 64bit EUI */
u8 max_rec; /* Sender's max packet size */
u8 sspd; /* Sender's max speed */
- u16 fifo_hi; /* hi 16bits of sender's FIFO addr */
- u32 fifo_lo; /* lo 32bits of sender's FIFO addr */
+ __be16 fifo_hi; /* hi 16bits of sender's FIFO addr */
+ __be32 fifo_lo; /* lo 32bits of sender's FIFO addr */
u32 sip; /* Sender's IP Address */
u32 tip; /* IP Address of requested hw addr */
};
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
index 272543a42a43..600e391c8fe7 100644
--- a/drivers/ieee1394/highlevel.c
+++ b/drivers/ieee1394/highlevel.c
@@ -320,7 +320,7 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
*/
u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
struct hpsb_host *host,
- struct hpsb_address_ops *ops,
+ const struct hpsb_address_ops *ops,
u64 size, u64 alignment,
u64 start, u64 end)
{
@@ -407,7 +407,8 @@ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
* are automatically deallocated together with the hpsb_highlevel @hl.
*/
int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
- struct hpsb_address_ops *ops, u64 start, u64 end)
+ const struct hpsb_address_ops *ops,
+ u64 start, u64 end)
{
struct hpsb_address_serve *as;
struct list_head *lh;
@@ -420,7 +421,7 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
return 0;
}
- as = kmalloc(sizeof(*as), GFP_ATOMIC);
+ as = kmalloc(sizeof(*as), GFP_KERNEL);
if (!as)
return 0;
@@ -477,7 +478,7 @@ int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
return retval;
}
-static struct hpsb_address_ops dummy_ops;
+const static struct hpsb_address_ops dummy_ops;
/* dummy address spaces as lower and upper bounds of the host's a.s. list */
static void init_hpsb_highlevel(struct hpsb_host *host)
diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
index bc5d0854c17e..9dba89fc60ad 100644
--- a/drivers/ieee1394/highlevel.h
+++ b/drivers/ieee1394/highlevel.h
@@ -15,7 +15,7 @@ struct hpsb_host;
struct hpsb_address_serve {
struct list_head host_list; /* per host list */
struct list_head hl_list; /* hpsb_highlevel list */
- struct hpsb_address_ops *op;
+ const struct hpsb_address_ops *op;
struct hpsb_host *host;
u64 start; /* first address handled, quadlet aligned */
u64 end; /* first address behind, quadlet aligned */
@@ -119,11 +119,12 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
struct hpsb_host *host,
- struct hpsb_address_ops *ops,
+ const struct hpsb_address_ops *ops,
u64 size, u64 alignment,
u64 start, u64 end);
int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
- struct hpsb_address_ops *ops, u64 start, u64 end);
+ const struct hpsb_address_ops *ops,
+ u64 start, u64 end);
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
u64 start);
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index 237d0c9d69c6..e947d8ffac85 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -34,18 +34,18 @@ static void delayed_reset_bus(struct work_struct *work)
{
struct hpsb_host *host =
container_of(work, struct hpsb_host, delayed_reset.work);
- int generation = host->csr.generation + 1;
+ u8 generation = host->csr.generation + 1;
/* The generation field rolls over to 2 rather than 0 per IEEE
* 1394a-2000. */
if (generation > 0xf || generation < 2)
generation = 2;
- CSR_SET_BUS_INFO_GENERATION(host->csr.rom, generation);
+ csr_set_bus_info_generation(host->csr.rom, generation);
if (csr1212_generate_csr_image(host->csr.rom) != CSR1212_SUCCESS) {
/* CSR image creation failed.
* Reset generation field and do not issue a bus reset. */
- CSR_SET_BUS_INFO_GENERATION(host->csr.rom,
+ csr_set_bus_info_generation(host->csr.rom,
host->csr.generation);
return;
}
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
index dd229950acca..49c359022c54 100644
--- a/drivers/ieee1394/hosts.h
+++ b/drivers/ieee1394/hosts.h
@@ -154,7 +154,7 @@ struct hpsb_host_driver {
* to set the hardware ConfigROM if the hardware supports handling
* reads to the ConfigROM on its own. */
void (*set_hw_config_rom)(struct hpsb_host *host,
- quadlet_t *config_rom);
+ __be32 *config_rom);
/* This function shall implement packet transmission based on
* packet->type. It shall CRC both parts of the packet (unless
diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h
index 40492074c013..e0ae0d3d747f 100644
--- a/drivers/ieee1394/ieee1394.h
+++ b/drivers/ieee1394/ieee1394.h
@@ -121,6 +121,9 @@ extern const char *hpsb_speedto_str[];
#include <asm/byteorder.h>
+/* '1' '3' '9' '4' in ASCII */
+#define IEEE1394_BUSID_MAGIC cpu_to_be32(0x31333934)
+
#ifdef __BIG_ENDIAN_BITFIELD
struct selfid {
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 79ef5fd928ae..906c5a98d814 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -67,7 +67,7 @@ static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
for (i = IEEE1394_SPEED_100; i <= old_speed; i++) {
*speed = i;
error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
- &q, sizeof(quadlet_t));
+ &q, 4);
if (error)
break;
*buffer = q;
@@ -85,7 +85,7 @@ static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
return error;
}
-static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
+static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr,
void *buffer, void *__ci)
{
struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
@@ -93,7 +93,7 @@ static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
for (i = 1; ; i++) {
error = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
- buffer, length);
+ buffer, 4);
if (!error) {
ci->speed_unverified = 0;
break;
@@ -104,7 +104,7 @@ static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
/* The ieee1394_core guessed the node's speed capability from
* the self ID. Check whether a lower speed works. */
- if (ci->speed_unverified && length == sizeof(quadlet_t)) {
+ if (ci->speed_unverified) {
error = nodemgr_check_speed(ci, addr, buffer);
if (!error)
break;
@@ -115,20 +115,8 @@ static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
return error;
}
-#define OUI_FREECOM_TECHNOLOGIES_GMBH 0x0001db
-
-static int nodemgr_get_max_rom(quadlet_t *bus_info_data, void *__ci)
-{
- /* Freecom FireWire Hard Drive firmware bug */
- if (be32_to_cpu(bus_info_data[3]) >> 8 == OUI_FREECOM_TECHNOLOGIES_GMBH)
- return 0;
-
- return (be32_to_cpu(bus_info_data[2]) >> 8) & 0x3;
-}
-
static struct csr1212_bus_ops nodemgr_csr_ops = {
.bus_read = nodemgr_bus_read,
- .get_max_rom = nodemgr_get_max_rom
};
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
index 4f287a3561ba..15ea09733e84 100644
--- a/drivers/ieee1394/nodemgr.h
+++ b/drivers/ieee1394/nodemgr.h
@@ -31,9 +31,6 @@ struct csr1212_keyval;
struct hpsb_host;
struct ieee1394_device_id;
-/* '1' '3' '9' '4' in ASCII */
-#define IEEE1394_BUSID_MAGIC __constant_cpu_to_be32(0x31333934)
-
/* This is the start of a Node entry structure. It should be a stable API
* for which to gather info from the Node Manager about devices attached
* to the bus. */
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index e509e13cb7a7..65c1429e4129 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -2973,7 +2973,7 @@ alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
return 0;
}
-static void ohci_set_hw_config_rom(struct hpsb_host *host, quadlet_t *config_rom)
+static void ohci_set_hw_config_rom(struct hpsb_host *host, __be32 *config_rom)
{
struct ti_ohci *ohci = host->hostdata;
@@ -3199,15 +3199,16 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
/* Now enable LPS, which we need in order to start accessing
* most of the registers. In fact, on some cards (ALI M5251),
* accessing registers in the SClk domain without LPS enabled
- * will lock up the machine. Wait 50msec to make sure we have
- * full link enabled. */
+ * will lock up the machine. */
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);
+ /* Flush MMIO writes and wait to make sure we have full link enabled. */
+ reg_read(ohci, OHCI1394_Version);
+ msleep(50);
/* Determine the number of available IR and IT contexts. */
ohci->nb_iso_rcv_ctx =
@@ -3233,8 +3234,9 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
* we need to get to that "no event", so enough should be initialized
* by that point.
*/
- if (request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED,
- OHCI1394_DRIVER_NAME, ohci)) {
+ err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED,
+ OHCI1394_DRIVER_NAME, ohci);
+ if (err) {
PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq);
goto err;
}
@@ -3381,6 +3383,7 @@ static int ohci1394_pci_suspend(struct pci_dev *dev, pm_message_t state)
ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT);
ohci_soft_reset(ohci);
+ free_irq(dev->irq, ohci);
err = pci_save_state(dev);
if (err) {
PRINT(KERN_ERR, "pci_save_state failed with %d", err);
@@ -3420,7 +3423,16 @@ static int ohci1394_pci_resume(struct pci_dev *dev)
reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff);
- mdelay(50);
+ reg_read(ohci, OHCI1394_Version);
+ msleep(50);
+
+ err = request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED,
+ OHCI1394_DRIVER_NAME, ohci);
+ if (err) {
+ PRINT_G(KERN_ERR, "Failed to allocate interrupt %d", dev->irq);
+ return err;
+ }
+
ohci_initialize(ohci);
hpsb_resume_host(ohci->host);
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index 7aee1ac97c80..dc15cadb06ef 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -1463,7 +1463,7 @@ static int __devinit add_card(struct pci_dev *dev,
/* info_length, crc_length and 1394 magic number to check, if it is really a bus info block */
if (((be32_to_cpu(lynx->bus_info_block[0]) & 0xffff0000) == 0x04040000) &&
- (lynx->bus_info_block[1] == __constant_cpu_to_be32(0x31333934)))
+ (lynx->bus_info_block[1] == IEEE1394_BUSID_MAGIC))
{
PRINT(KERN_DEBUG, lynx->id, "read a valid bus info block from");
} else {
diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h
index ec27321f6724..693a169acea3 100644
--- a/drivers/ieee1394/pcilynx.h
+++ b/drivers/ieee1394/pcilynx.h
@@ -52,7 +52,7 @@ struct ti_lynx {
void __iomem *local_rom;
void __iomem *local_ram;
void __iomem *aux_port;
- quadlet_t bus_info_block[5];
+ __be32 bus_info_block[5];
/*
* use local RAM of LOCALRAM_SIZE bytes for PCLs, which allows for
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index bf7e761c12b1..bad66c65b0d6 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -90,7 +90,7 @@ static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store,
static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store,
u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
u16 flags);
-static struct hpsb_address_ops arm_ops = {
+const static struct hpsb_address_ops arm_ops = {
.read = arm_read,
.write = arm_write,
.lock = arm_lock,
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index a373c18cf7b8..ab1034ccb7fb 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -265,7 +265,7 @@ static struct hpsb_highlevel sbp2_highlevel = {
.host_reset = sbp2_host_reset,
};
-static struct hpsb_address_ops sbp2_ops = {
+const static struct hpsb_address_ops sbp2_ops = {
.write = sbp2_handle_status_write
};
@@ -275,7 +275,7 @@ static int sbp2_handle_physdma_write(struct hpsb_host *, int, int, quadlet_t *,
static int sbp2_handle_physdma_read(struct hpsb_host *, int, quadlet_t *, u64,
size_t, u16);
-static struct hpsb_address_ops sbp2_physdma_ops = {
+const static struct hpsb_address_ops sbp2_physdma_ops = {
.read = sbp2_handle_physdma_read,
.write = sbp2_handle_physdma_write,
};
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 2f4c28a30271..97e4b231cdc4 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -196,7 +196,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
if (h_ret != H_SUCCESS) {
ehca_err(device, "hipz_h_alloc_resource_cq() failed "
- "h_ret=%li device=%p", h_ret, device);
+ "h_ret=%lli device=%p", h_ret, device);
cq = ERR_PTR(ehca2ib_return_code(h_ret));
goto create_cq_exit2;
}
@@ -232,7 +232,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
if (h_ret < H_SUCCESS) {
ehca_err(device, "hipz_h_register_rpage_cq() failed "
- "ehca_cq=%p cq_num=%x h_ret=%li counter=%i "
+ "ehca_cq=%p cq_num=%x h_ret=%lli counter=%i "
"act_pages=%i", my_cq, my_cq->cq_number,
h_ret, counter, param.act_pages);
cq = ERR_PTR(-EINVAL);
@@ -244,7 +244,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
if ((h_ret != H_SUCCESS) || vpage) {
ehca_err(device, "Registration of pages not "
"complete ehca_cq=%p cq_num=%x "
- "h_ret=%li", my_cq, my_cq->cq_number,
+ "h_ret=%lli", my_cq, my_cq->cq_number,
h_ret);
cq = ERR_PTR(-EAGAIN);
goto create_cq_exit4;
@@ -252,7 +252,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=%lli "
"counter=%i act_pages=%i",
my_cq, my_cq->cq_number,
h_ret, counter, param.act_pages);
@@ -266,7 +266,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
gal = my_cq->galpas.kernel;
cqx_fec = hipz_galpa_load(gal, CQTEMM_OFFSET(cqx_fec));
- ehca_dbg(device, "ehca_cq=%p cq_num=%x CQX_FEC=%lx",
+ ehca_dbg(device, "ehca_cq=%p cq_num=%x CQX_FEC=%llx",
my_cq, my_cq->cq_number, cqx_fec);
my_cq->ib_cq.cqe = my_cq->nr_of_entries =
@@ -307,7 +307,7 @@ create_cq_exit3:
h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
if (h_ret != H_SUCCESS)
ehca_err(device, "hipz_h_destroy_cq() failed ehca_cq=%p "
- "cq_num=%x h_ret=%li", my_cq, my_cq->cq_number, h_ret);
+ "cq_num=%x h_ret=%lli", my_cq, my_cq->cq_number, h_ret);
create_cq_exit2:
write_lock_irqsave(&ehca_cq_idr_lock, flags);
@@ -355,7 +355,7 @@ int ehca_destroy_cq(struct ib_cq *cq)
h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0);
if (h_ret == H_R_STATE) {
/* cq in err: read err data and destroy it forcibly */
- ehca_dbg(device, "ehca_cq=%p cq_num=%x ressource=%lx in err "
+ ehca_dbg(device, "ehca_cq=%p cq_num=%x resource=%llx in err "
"state. Try to delete it forcibly.",
my_cq, cq_num, my_cq->ipz_cq_handle.handle);
ehca_error_data(shca, my_cq, my_cq->ipz_cq_handle.handle);
@@ -365,7 +365,7 @@ int ehca_destroy_cq(struct ib_cq *cq)
cq_num);
}
if (h_ret != H_SUCCESS) {
- ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%li "
+ ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%lli "
"ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num);
return ehca2ib_return_code(h_ret);
}
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
index 46288220cfbb..9209c5332dfe 100644
--- a/drivers/infiniband/hw/ehca/ehca_hca.c
+++ b/drivers/infiniband/hw/ehca/ehca_hca.c
@@ -393,7 +393,7 @@ int ehca_modify_port(struct ib_device *ibdev,
hret = hipz_h_modify_port(shca->ipz_hca_handle, port,
cap, props->init_type, port_modify_mask);
if (hret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "Modify port failed h_ret=%li",
+ ehca_err(&shca->ib_device, "Modify port failed h_ret=%lli",
hret);
ret = -EINVAL;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index 3128a5090dbd..99bcbd7ffb0a 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -99,7 +99,7 @@ static void print_error_data(struct ehca_shca *shca, void *data,
return;
ehca_err(&shca->ib_device,
- "QP 0x%x (resource=%lx) has errors.",
+ "QP 0x%x (resource=%llx) has errors.",
qp->ib_qp.qp_num, resource);
break;
}
@@ -108,21 +108,21 @@ static void print_error_data(struct ehca_shca *shca, void *data,
struct ehca_cq *cq = (struct ehca_cq *)data;
ehca_err(&shca->ib_device,
- "CQ 0x%x (resource=%lx) has errors.",
+ "CQ 0x%x (resource=%llx) has errors.",
cq->cq_number, resource);
break;
}
default:
ehca_err(&shca->ib_device,
- "Unknown error type: %lx on %s.",
+ "Unknown error type: %llx on %s.",
type, shca->ib_device.name);
break;
}
- ehca_err(&shca->ib_device, "Error data is available: %lx.", resource);
+ ehca_err(&shca->ib_device, "Error data is available: %llx.", resource);
ehca_err(&shca->ib_device, "EHCA ----- error data begin "
"---------------------------------------------------");
- ehca_dmp(rblock, length, "resource=%lx", resource);
+ ehca_dmp(rblock, length, "resource=%llx", resource);
ehca_err(&shca->ib_device, "EHCA ----- error data end "
"----------------------------------------------------");
@@ -152,7 +152,7 @@ int ehca_error_data(struct ehca_shca *shca, void *data,
if (ret == H_R_STATE)
ehca_err(&shca->ib_device,
- "No error data is available: %lx.", resource);
+ "No error data is available: %llx.", resource);
else if (ret == H_SUCCESS) {
int length;
@@ -164,7 +164,7 @@ int ehca_error_data(struct ehca_shca *shca, void *data,
print_error_data(shca, data, rblock, length);
} else
ehca_err(&shca->ib_device,
- "Error data could not be fetched: %lx", resource);
+ "Error data could not be fetched: %llx", resource);
ehca_free_fw_ctrlblock(rblock);
@@ -514,7 +514,7 @@ static inline void process_eqe(struct ehca_shca *shca, struct ehca_eqe *eqe)
struct ehca_cq *cq;
eqe_value = eqe->entry;
- ehca_dbg(&shca->ib_device, "eqe_value=%lx", eqe_value);
+ ehca_dbg(&shca->ib_device, "eqe_value=%llx", eqe_value);
if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) {
ehca_dbg(&shca->ib_device, "Got completion event");
token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value);
@@ -603,7 +603,7 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq)
ret = hipz_h_eoi(eq->ist);
if (ret != H_SUCCESS)
ehca_err(&shca->ib_device,
- "bad return code EOI -rc = %ld\n", ret);
+ "bad return code EOI -rc = %lld\n", ret);
ehca_dbg(&shca->ib_device, "deadman found %x eqe", eqe_cnt);
}
if (unlikely(eqe_cnt == EHCA_EQE_CACHE_SIZE))
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 3b77b674cbf6..368311ce332b 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -304,7 +304,7 @@ static int ehca_sense_attributes(struct ehca_shca *shca)
h_ret = hipz_h_query_hca(shca->ipz_hca_handle, rblock);
if (h_ret != H_SUCCESS) {
- ehca_gen_err("Cannot query device properties. h_ret=%li",
+ ehca_gen_err("Cannot query device properties. h_ret=%lli",
h_ret);
ret = -EPERM;
goto sense_attributes1;
@@ -391,7 +391,7 @@ static int ehca_sense_attributes(struct ehca_shca *shca)
port = (struct hipz_query_port *)rblock;
h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port);
if (h_ret != H_SUCCESS) {
- ehca_gen_err("Cannot query port properties. h_ret=%li",
+ ehca_gen_err("Cannot query port properties. h_ret=%lli",
h_ret);
ret = -EPERM;
goto sense_attributes1;
@@ -682,7 +682,7 @@ static ssize_t ehca_show_adapter_handle(struct device *dev,
{
struct ehca_shca *shca = dev->driver_data;
- return sprintf(buf, "%lx\n", shca->ipz_hca_handle.handle);
+ return sprintf(buf, "%llx\n", shca->ipz_hca_handle.handle);
}
static DEVICE_ATTR(adapter_handle, S_IRUGO, ehca_show_adapter_handle, NULL);
@@ -955,7 +955,7 @@ void ehca_poll_eqs(unsigned long data)
struct ehca_eq *eq = &shca->eq;
int max = 3;
volatile u64 q_ofs, q_ofs2;
- u64 flags;
+ unsigned long flags;
spin_lock_irqsave(&eq->spinlock, flags);
q_ofs = eq->ipz_queue.current_q_offset;
spin_unlock_irqrestore(&eq->spinlock, flags);
diff --git a/drivers/infiniband/hw/ehca/ehca_mcast.c b/drivers/infiniband/hw/ehca/ehca_mcast.c
index e3ef0264ccc6..120aedf9f989 100644
--- a/drivers/infiniband/hw/ehca/ehca_mcast.c
+++ b/drivers/infiniband/hw/ehca/ehca_mcast.c
@@ -88,7 +88,7 @@ int ehca_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
if (h_ret != H_SUCCESS)
ehca_err(ibqp->device,
"ehca_qp=%p qp_num=%x hipz_h_attach_mcqp() failed "
- "h_ret=%li", my_qp, ibqp->qp_num, h_ret);
+ "h_ret=%lli", my_qp, ibqp->qp_num, h_ret);
return ehca2ib_return_code(h_ret);
}
@@ -125,7 +125,7 @@ int ehca_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
if (h_ret != H_SUCCESS)
ehca_err(ibqp->device,
"ehca_qp=%p qp_num=%x hipz_h_detach_mcqp() failed "
- "h_ret=%li", my_qp, ibqp->qp_num, h_ret);
+ "h_ret=%lli", my_qp, ibqp->qp_num, h_ret);
return ehca2ib_return_code(h_ret);
}
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
index f974367cad40..72f83f7df614 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.c
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -204,7 +204,7 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
}
if ((size == 0) ||
(((u64)iova_start + size) < (u64)iova_start)) {
- ehca_err(pd->device, "bad input values: size=%lx iova_start=%p",
+ ehca_err(pd->device, "bad input values: size=%llx iova_start=%p",
size, iova_start);
ib_mr = ERR_PTR(-EINVAL);
goto reg_phys_mr_exit0;
@@ -309,8 +309,8 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
}
if (length == 0 || virt + length < virt) {
- ehca_err(pd->device, "bad input values: length=%lx "
- "virt_base=%lx", length, virt);
+ ehca_err(pd->device, "bad input values: length=%llx "
+ "virt_base=%llx", length, virt);
ib_mr = ERR_PTR(-EINVAL);
goto reg_user_mr_exit0;
}
@@ -373,7 +373,7 @@ reg_user_mr_fallback:
&e_mr->ib.ib_mr.rkey);
if (ret == -EINVAL && pginfo.hwpage_size > PAGE_SIZE) {
ehca_warn(pd->device, "failed to register mr "
- "with hwpage_size=%lx", hwpage_size);
+ "with hwpage_size=%llx", hwpage_size);
ehca_info(pd->device, "try to register mr with "
"kpage_size=%lx", PAGE_SIZE);
/*
@@ -509,7 +509,7 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
goto rereg_phys_mr_exit1;
if ((new_size == 0) ||
(((u64)iova_start + new_size) < (u64)iova_start)) {
- ehca_err(mr->device, "bad input values: new_size=%lx "
+ ehca_err(mr->device, "bad input values: new_size=%llx "
"iova_start=%p", new_size, iova_start);
ret = -EINVAL;
goto rereg_phys_mr_exit1;
@@ -580,8 +580,8 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
h_ret = hipz_h_query_mr(shca->ipz_hca_handle, e_mr, &hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(mr->device, "hipz_mr_query failed, h_ret=%li mr=%p "
- "hca_hndl=%lx mr_hndl=%lx lkey=%x",
+ ehca_err(mr->device, "hipz_mr_query failed, h_ret=%lli mr=%p "
+ "hca_hndl=%llx mr_hndl=%llx lkey=%x",
h_ret, mr, shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle, mr->lkey);
ret = ehca2ib_return_code(h_ret);
@@ -630,8 +630,8 @@ int ehca_dereg_mr(struct ib_mr *mr)
/* TODO: BUSY: MR still has bound window(s) */
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
if (h_ret != H_SUCCESS) {
- ehca_err(mr->device, "hipz_free_mr failed, h_ret=%li shca=%p "
- "e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x",
+ ehca_err(mr->device, "hipz_free_mr failed, h_ret=%lli shca=%p "
+ "e_mr=%p hca_hndl=%llx mr_hndl=%llx mr->lkey=%x",
h_ret, shca, e_mr, shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle, mr->lkey);
ret = ehca2ib_return_code(h_ret);
@@ -671,8 +671,8 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd)
h_ret = hipz_h_alloc_resource_mw(shca->ipz_hca_handle, e_mw,
e_pd->fw_pd, &hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%li "
- "shca=%p hca_hndl=%lx mw=%p",
+ ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lli "
+ "shca=%p hca_hndl=%llx mw=%p",
h_ret, shca, shca->ipz_hca_handle.handle, e_mw);
ib_mw = ERR_PTR(ehca2ib_return_code(h_ret));
goto alloc_mw_exit1;
@@ -713,8 +713,8 @@ int ehca_dealloc_mw(struct ib_mw *mw)
h_ret = hipz_h_free_resource_mw(shca->ipz_hca_handle, e_mw);
if (h_ret != H_SUCCESS) {
- ehca_err(mw->device, "hipz_free_mw failed, h_ret=%li shca=%p "
- "mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx",
+ ehca_err(mw->device, "hipz_free_mw failed, h_ret=%lli shca=%p "
+ "mw=%p rkey=%x hca_hndl=%llx mw_hndl=%llx",
h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle,
e_mw->ipz_mw_handle.handle);
return ehca2ib_return_code(h_ret);
@@ -840,7 +840,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
goto map_phys_fmr_exit0;
if (iova % e_fmr->fmr_page_size) {
/* only whole-numbered pages */
- ehca_err(fmr->device, "bad iova, iova=%lx fmr_page_size=%x",
+ ehca_err(fmr->device, "bad iova, iova=%llx fmr_page_size=%x",
iova, e_fmr->fmr_page_size);
ret = -EINVAL;
goto map_phys_fmr_exit0;
@@ -878,7 +878,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
map_phys_fmr_exit0:
if (ret)
ehca_err(fmr->device, "ret=%i fmr=%p page_list=%p list_len=%x "
- "iova=%lx", ret, fmr, page_list, list_len, iova);
+ "iova=%llx", ret, fmr, page_list, list_len, iova);
return ret;
} /* end ehca_map_phys_fmr() */
@@ -964,8 +964,8 @@ int ehca_dealloc_fmr(struct ib_fmr *fmr)
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
if (h_ret != H_SUCCESS) {
- ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%li e_fmr=%p "
- "hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x",
+ ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%lli e_fmr=%p "
+ "hca_hndl=%llx fmr_hndl=%llx fmr->lkey=%x",
h_ret, e_fmr, shca->ipz_hca_handle.handle,
e_fmr->ipz_mr_handle.handle, fmr->lkey);
ret = ehca2ib_return_code(h_ret);
@@ -1007,8 +1007,8 @@ int ehca_reg_mr(struct ehca_shca *shca,
(u64)iova_start, size, hipz_acl,
e_pd->fw_pd, &hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%li "
- "hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle);
+ ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lli "
+ "hca_hndl=%llx", h_ret, shca->ipz_hca_handle.handle);
ret = ehca2ib_return_code(h_ret);
goto ehca_reg_mr_exit0;
}
@@ -1033,9 +1033,9 @@ int ehca_reg_mr(struct ehca_shca *shca,
ehca_reg_mr_exit1:
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "h_ret=%li shca=%p e_mr=%p "
- "iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x "
- "pginfo=%p num_kpages=%lx num_hwpages=%lx ret=%i",
+ ehca_err(&shca->ib_device, "h_ret=%lli shca=%p e_mr=%p "
+ "iova_start=%p size=%llx acl=%x e_pd=%p lkey=%x "
+ "pginfo=%p num_kpages=%llx num_hwpages=%llx ret=%i",
h_ret, shca, e_mr, iova_start, size, acl, e_pd,
hipzout.lkey, pginfo, pginfo->num_kpages,
pginfo->num_hwpages, ret);
@@ -1045,8 +1045,8 @@ ehca_reg_mr_exit1:
ehca_reg_mr_exit0:
if (ret)
ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p "
- "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
- "num_kpages=%lx num_hwpages=%lx",
+ "iova_start=%p size=%llx acl=%x e_pd=%p pginfo=%p "
+ "num_kpages=%llx num_hwpages=%llx",
ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo,
pginfo->num_kpages, pginfo->num_hwpages);
return ret;
@@ -1116,8 +1116,8 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
*/
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "last "
- "hipz_reg_rpage_mr failed, h_ret=%li "
- "e_mr=%p i=%x hca_hndl=%lx mr_hndl=%lx"
+ "hipz_reg_rpage_mr failed, h_ret=%lli "
+ "e_mr=%p i=%x hca_hndl=%llx mr_hndl=%llx"
" lkey=%x", h_ret, e_mr, i,
shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle,
@@ -1128,8 +1128,8 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
ret = 0;
} else if (h_ret != H_PAGE_REGISTERED) {
ehca_err(&shca->ib_device, "hipz_reg_rpage_mr failed, "
- "h_ret=%li e_mr=%p i=%x lkey=%x hca_hndl=%lx "
- "mr_hndl=%lx", h_ret, e_mr, i,
+ "h_ret=%lli e_mr=%p i=%x lkey=%x hca_hndl=%llx "
+ "mr_hndl=%llx", h_ret, e_mr, i,
e_mr->ib.ib_mr.lkey,
shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle);
@@ -1145,7 +1145,7 @@ ehca_reg_mr_rpages_exit1:
ehca_reg_mr_rpages_exit0:
if (ret)
ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p pginfo=%p "
- "num_kpages=%lx num_hwpages=%lx", ret, shca, e_mr,
+ "num_kpages=%llx num_hwpages=%llx", ret, shca, e_mr,
pginfo, pginfo->num_kpages, pginfo->num_hwpages);
return ret;
} /* end ehca_reg_mr_rpages() */
@@ -1184,7 +1184,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
ret = ehca_set_pagebuf(pginfo, pginfo->num_hwpages, kpage);
if (ret) {
ehca_err(&shca->ib_device, "set pagebuf failed, e_mr=%p "
- "pginfo=%p type=%x num_kpages=%lx num_hwpages=%lx "
+ "pginfo=%p type=%x num_kpages=%llx num_hwpages=%llx "
"kpage=%p", e_mr, pginfo, pginfo->type,
pginfo->num_kpages, pginfo->num_hwpages, kpage);
goto ehca_rereg_mr_rereg1_exit1;
@@ -1205,13 +1205,13 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
* (MW bound or MR is shared)
*/
ehca_warn(&shca->ib_device, "hipz_h_reregister_pmr failed "
- "(Rereg1), h_ret=%li e_mr=%p", h_ret, e_mr);
+ "(Rereg1), h_ret=%lli e_mr=%p", h_ret, e_mr);
*pginfo = pginfo_save;
ret = -EAGAIN;
} else if ((u64 *)hipzout.vaddr != iova_start) {
ehca_err(&shca->ib_device, "PHYP changed iova_start in "
- "rereg_pmr, iova_start=%p iova_start_out=%lx e_mr=%p "
- "mr_handle=%lx lkey=%x lkey_out=%x", iova_start,
+ "rereg_pmr, iova_start=%p iova_start_out=%llx e_mr=%p "
+ "mr_handle=%llx lkey=%x lkey_out=%x", iova_start,
hipzout.vaddr, e_mr, e_mr->ipz_mr_handle.handle,
e_mr->ib.ib_mr.lkey, hipzout.lkey);
ret = -EFAULT;
@@ -1235,7 +1235,7 @@ ehca_rereg_mr_rereg1_exit1:
ehca_rereg_mr_rereg1_exit0:
if ( ret && (ret != -EAGAIN) )
ehca_err(&shca->ib_device, "ret=%i lkey=%x rkey=%x "
- "pginfo=%p num_kpages=%lx num_hwpages=%lx",
+ "pginfo=%p num_kpages=%llx num_hwpages=%llx",
ret, *lkey, *rkey, pginfo, pginfo->num_kpages,
pginfo->num_hwpages);
return ret;
@@ -1263,7 +1263,7 @@ int ehca_rereg_mr(struct ehca_shca *shca,
(e_mr->num_hwpages > MAX_RPAGES) ||
(pginfo->num_hwpages > e_mr->num_hwpages)) {
ehca_dbg(&shca->ib_device, "Rereg3 case, "
- "pginfo->num_hwpages=%lx e_mr->num_hwpages=%x",
+ "pginfo->num_hwpages=%llx e_mr->num_hwpages=%x",
pginfo->num_hwpages, e_mr->num_hwpages);
rereg_1_hcall = 0;
rereg_3_hcall = 1;
@@ -1295,7 +1295,7 @@ int ehca_rereg_mr(struct ehca_shca *shca,
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "hipz_free_mr failed, "
- "h_ret=%li e_mr=%p hca_hndl=%lx mr_hndl=%lx "
+ "h_ret=%lli e_mr=%p hca_hndl=%llx mr_hndl=%llx "
"mr->lkey=%x",
h_ret, e_mr, shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle,
@@ -1328,8 +1328,8 @@ int ehca_rereg_mr(struct ehca_shca *shca,
ehca_rereg_mr_exit0:
if (ret)
ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p "
- "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
- "num_kpages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
+ "iova_start=%p size=%llx acl=%x e_pd=%p pginfo=%p "
+ "num_kpages=%llx lkey=%x rkey=%x rereg_1_hcall=%x "
"rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size,
acl, e_pd, pginfo, pginfo->num_kpages, *lkey, *rkey,
rereg_1_hcall, rereg_3_hcall);
@@ -1371,8 +1371,8 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca,
* FMRs are not shared and no MW bound to FMRs
*/
ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
- "(Rereg1), h_ret=%li e_fmr=%p hca_hndl=%lx "
- "mr_hndl=%lx lkey=%x lkey_out=%x",
+ "(Rereg1), h_ret=%lli e_fmr=%p hca_hndl=%llx "
+ "mr_hndl=%llx lkey=%x lkey_out=%x",
h_ret, e_fmr, shca->ipz_hca_handle.handle,
e_fmr->ipz_mr_handle.handle,
e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
@@ -1383,7 +1383,7 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca,
h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "hipz_free_mr failed, "
- "h_ret=%li e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
+ "h_ret=%lli e_fmr=%p hca_hndl=%llx mr_hndl=%llx "
"lkey=%x",
h_ret, e_fmr, shca->ipz_hca_handle.handle,
e_fmr->ipz_mr_handle.handle,
@@ -1447,9 +1447,9 @@ int ehca_reg_smr(struct ehca_shca *shca,
(u64)iova_start, hipz_acl, e_pd->fw_pd,
&hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%li "
+ ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lli "
"shca=%p e_origmr=%p e_newmr=%p iova_start=%p acl=%x "
- "e_pd=%p hca_hndl=%lx mr_hndl=%lx lkey=%x",
+ "e_pd=%p hca_hndl=%llx mr_hndl=%llx lkey=%x",
h_ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd,
shca->ipz_hca_handle.handle,
e_origmr->ipz_mr_handle.handle,
@@ -1527,7 +1527,7 @@ int ehca_reg_internal_maxmr(
&e_mr->ib.ib_mr.rkey);
if (ret) {
ehca_err(&shca->ib_device, "reg of internal max MR failed, "
- "e_mr=%p iova_start=%p size_maxmr=%lx num_kpages=%x "
+ "e_mr=%p iova_start=%p size_maxmr=%llx num_kpages=%x "
"num_hwpages=%x", e_mr, iova_start, size_maxmr,
num_kpages, num_hwpages);
goto ehca_reg_internal_maxmr_exit1;
@@ -1573,8 +1573,8 @@ int ehca_reg_maxmr(struct ehca_shca *shca,
(u64)iova_start, hipz_acl, e_pd->fw_pd,
&hipzout);
if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%li "
- "e_origmr=%p hca_hndl=%lx mr_hndl=%lx lkey=%x",
+ ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lli "
+ "e_origmr=%p hca_hndl=%llx mr_hndl=%llx lkey=%x",
h_ret, e_origmr, shca->ipz_hca_handle.handle,
e_origmr->ipz_mr_handle.handle,
e_origmr->ib.ib_mr.lkey);
@@ -1651,28 +1651,28 @@ int ehca_mr_chk_buf_and_calc_size(struct ib_phys_buf *phys_buf_array,
/* check first buffer */
if (((u64)iova_start & ~PAGE_MASK) != (pbuf->addr & ~PAGE_MASK)) {
ehca_gen_err("iova_start/addr mismatch, iova_start=%p "
- "pbuf->addr=%lx pbuf->size=%lx",
+ "pbuf->addr=%llx pbuf->size=%llx",
iova_start, pbuf->addr, pbuf->size);
return -EINVAL;
}
if (((pbuf->addr + pbuf->size) % PAGE_SIZE) &&
(num_phys_buf > 1)) {
- ehca_gen_err("addr/size mismatch in 1st buf, pbuf->addr=%lx "
- "pbuf->size=%lx", pbuf->addr, pbuf->size);
+ ehca_gen_err("addr/size mismatch in 1st buf, pbuf->addr=%llx "
+ "pbuf->size=%llx", pbuf->addr, pbuf->size);
return -EINVAL;
}
for (i = 0; i < num_phys_buf; i++) {
if ((i > 0) && (pbuf->addr % PAGE_SIZE)) {
- ehca_gen_err("bad address, i=%x pbuf->addr=%lx "
- "pbuf->size=%lx",
+ ehca_gen_err("bad address, i=%x pbuf->addr=%llx "
+ "pbuf->size=%llx",
i, pbuf->addr, pbuf->size);
return -EINVAL;
}
if (((i > 0) && /* not 1st */
(i < (num_phys_buf - 1)) && /* not last */
(pbuf->size % PAGE_SIZE)) || (pbuf->size == 0)) {
- ehca_gen_err("bad size, i=%x pbuf->size=%lx",
+ ehca_gen_err("bad size, i=%x pbuf->size=%llx",
i, pbuf->size);
return -EINVAL;
}
@@ -1705,7 +1705,7 @@ int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
page = page_list;
for (i = 0; i < list_len; i++) {
if (*page % e_fmr->fmr_page_size) {
- ehca_gen_err("bad page, i=%x *page=%lx page=%p fmr=%p "
+ ehca_gen_err("bad page, i=%x *page=%llx page=%p fmr=%p "
"fmr_page_size=%x", i, *page, page, e_fmr,
e_fmr->fmr_page_size);
return -EINVAL;
@@ -1743,9 +1743,9 @@ static int ehca_set_pagebuf_user1(struct ehca_mr_pginfo *pginfo,
(pginfo->next_hwpage *
pginfo->hwpage_size));
if ( !(*kpage) ) {
- ehca_gen_err("pgaddr=%lx "
- "chunk->page_list[i]=%lx "
- "i=%x next_hwpage=%lx",
+ ehca_gen_err("pgaddr=%llx "
+ "chunk->page_list[i]=%llx "
+ "i=%x next_hwpage=%llx",
pgaddr, (u64)sg_dma_address(
&chunk->page_list[i]),
i, pginfo->next_hwpage);
@@ -1795,11 +1795,11 @@ static int ehca_check_kpages_per_ate(struct scatterlist *page_list,
for (t = start_idx; t <= end_idx; t++) {
u64 pgaddr = page_to_pfn(sg_page(&page_list[t])) << PAGE_SHIFT;
if (ehca_debug_level >= 3)
- ehca_gen_dbg("chunk_page=%lx value=%016lx", pgaddr,
+ ehca_gen_dbg("chunk_page=%llx value=%016llx", pgaddr,
*(u64 *)abs_to_virt(phys_to_abs(pgaddr)));
if (pgaddr - PAGE_SIZE != *prev_pgaddr) {
- ehca_gen_err("uncontiguous page found pgaddr=%lx "
- "prev_pgaddr=%lx page_list_i=%x",
+ ehca_gen_err("uncontiguous page found pgaddr=%llx "
+ "prev_pgaddr=%llx page_list_i=%x",
pgaddr, *prev_pgaddr, t);
return -EINVAL;
}
@@ -1833,7 +1833,7 @@ static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo,
<< PAGE_SHIFT );
*kpage = phys_to_abs(pgaddr);
if ( !(*kpage) ) {
- ehca_gen_err("pgaddr=%lx i=%x",
+ ehca_gen_err("pgaddr=%llx i=%x",
pgaddr, i);
ret = -EFAULT;
return ret;
@@ -1846,8 +1846,8 @@ static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo,
if (pginfo->hwpage_cnt) {
ehca_gen_err(
"invalid alignment "
- "pgaddr=%lx i=%x "
- "mr_pgsize=%lx",
+ "pgaddr=%llx i=%x "
+ "mr_pgsize=%llx",
pgaddr, i,
pginfo->hwpage_size);
ret = -EFAULT;
@@ -1866,8 +1866,8 @@ static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo,
if (ehca_debug_level >= 3) {
u64 val = *(u64 *)abs_to_virt(
phys_to_abs(pgaddr));
- ehca_gen_dbg("kpage=%lx chunk_page=%lx "
- "value=%016lx",
+ ehca_gen_dbg("kpage=%llx chunk_page=%llx "
+ "value=%016llx",
*kpage, pgaddr, val);
}
prev_pgaddr = pgaddr;
@@ -1944,9 +1944,9 @@ static int ehca_set_pagebuf_phys(struct ehca_mr_pginfo *pginfo,
if ((pginfo->kpage_cnt >= pginfo->num_kpages) ||
(pginfo->hwpage_cnt >= pginfo->num_hwpages)) {
ehca_gen_err("kpage_cnt >= num_kpages, "
- "kpage_cnt=%lx num_kpages=%lx "
- "hwpage_cnt=%lx "
- "num_hwpages=%lx i=%x",
+ "kpage_cnt=%llx num_kpages=%llx "
+ "hwpage_cnt=%llx "
+ "num_hwpages=%llx i=%x",
pginfo->kpage_cnt,
pginfo->num_kpages,
pginfo->hwpage_cnt,
@@ -1957,8 +1957,8 @@ static int ehca_set_pagebuf_phys(struct ehca_mr_pginfo *pginfo,
(pbuf->addr & ~(pginfo->hwpage_size - 1)) +
(pginfo->next_hwpage * pginfo->hwpage_size));
if ( !(*kpage) && pbuf->addr ) {
- ehca_gen_err("pbuf->addr=%lx pbuf->size=%lx "
- "next_hwpage=%lx", pbuf->addr,
+ ehca_gen_err("pbuf->addr=%llx pbuf->size=%llx "
+ "next_hwpage=%llx", pbuf->addr,
pbuf->size, pginfo->next_hwpage);
return -EFAULT;
}
@@ -1996,8 +1996,8 @@ static int ehca_set_pagebuf_fmr(struct ehca_mr_pginfo *pginfo,
*kpage = phys_to_abs((*fmrlist & ~(pginfo->hwpage_size - 1)) +
pginfo->next_hwpage * pginfo->hwpage_size);
if ( !(*kpage) ) {
- ehca_gen_err("*fmrlist=%lx fmrlist=%p "
- "next_listelem=%lx next_hwpage=%lx",
+ ehca_gen_err("*fmrlist=%llx fmrlist=%p "
+ "next_listelem=%llx next_hwpage=%llx",
*fmrlist, fmrlist,
pginfo->u.fmr.next_listelem,
pginfo->next_hwpage);
@@ -2025,7 +2025,7 @@ static int ehca_set_pagebuf_fmr(struct ehca_mr_pginfo *pginfo,
~(pginfo->hwpage_size - 1));
if (prev + pginfo->u.fmr.fmr_pgsize != p) {
ehca_gen_err("uncontiguous fmr pages "
- "found prev=%lx p=%lx "
+ "found prev=%llx p=%llx "
"idx=%x", prev, p, i + j);
return -EINVAL;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index f161cf173dbe..00c108159714 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -331,7 +331,7 @@ static inline int init_qp_queue(struct ehca_shca *shca,
if (cnt == (nr_q_pages - 1)) { /* last page! */
if (h_ret != expected_hret) {
ehca_err(ib_dev, "hipz_qp_register_rpage() "
- "h_ret=%li", h_ret);
+ "h_ret=%lli", h_ret);
ret = ehca2ib_return_code(h_ret);
goto init_qp_queue1;
}
@@ -345,7 +345,7 @@ static inline int init_qp_queue(struct ehca_shca *shca,
} else {
if (h_ret != H_PAGE_REGISTERED) {
ehca_err(ib_dev, "hipz_qp_register_rpage() "
- "h_ret=%li", h_ret);
+ "h_ret=%lli", h_ret);
ret = ehca2ib_return_code(h_ret);
goto init_qp_queue1;
}
@@ -709,7 +709,7 @@ static struct ehca_qp *internal_create_qp(
h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms);
if (h_ret != H_SUCCESS) {
- ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%li",
+ ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%lli",
h_ret);
ret = ehca2ib_return_code(h_ret);
goto create_qp_exit1;
@@ -1010,7 +1010,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
mqpcb, my_qp->galpas.kernel);
if (hret != H_SUCCESS) {
ehca_err(pd->device, "Could not modify SRQ to INIT "
- "ehca_qp=%p qp_num=%x h_ret=%li",
+ "ehca_qp=%p qp_num=%x h_ret=%lli",
my_qp, my_qp->real_qp_num, hret);
goto create_srq2;
}
@@ -1024,7 +1024,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
mqpcb, my_qp->galpas.kernel);
if (hret != H_SUCCESS) {
ehca_err(pd->device, "Could not enable SRQ "
- "ehca_qp=%p qp_num=%x h_ret=%li",
+ "ehca_qp=%p qp_num=%x h_ret=%lli",
my_qp, my_qp->real_qp_num, hret);
goto create_srq2;
}
@@ -1038,7 +1038,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd,
mqpcb, my_qp->galpas.kernel);
if (hret != H_SUCCESS) {
ehca_err(pd->device, "Could not modify SRQ to RTR "
- "ehca_qp=%p qp_num=%x h_ret=%li",
+ "ehca_qp=%p qp_num=%x h_ret=%lli",
my_qp, my_qp->real_qp_num, hret);
goto create_srq2;
}
@@ -1078,7 +1078,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
&bad_send_wqe_p, NULL, 2);
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "hipz_h_disable_and_get_wqe() failed"
- " ehca_qp=%p qp_num=%x h_ret=%li",
+ " ehca_qp=%p qp_num=%x h_ret=%lli",
my_qp, qp_num, h_ret);
return ehca2ib_return_code(h_ret);
}
@@ -1134,7 +1134,7 @@ static int calc_left_cqes(u64 wqe_p, struct ipz_queue *ipz_queue,
if (ipz_queue_abs_to_offset(ipz_queue, wqe_p, &q_ofs)) {
ehca_gen_err("Invalid offset for calculating left cqes "
- "wqe_p=%#lx wqe_v=%p\n", wqe_p, wqe_v);
+ "wqe_p=%#llx wqe_v=%p\n", wqe_p, wqe_v);
return -EFAULT;
}
@@ -1168,7 +1168,7 @@ static int check_for_left_cqes(struct ehca_qp *my_qp, struct ehca_shca *shca)
&send_wqe_p, &recv_wqe_p, 4);
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "disable_and_get_wqe() "
- "failed ehca_qp=%p qp_num=%x h_ret=%li",
+ "failed ehca_qp=%p qp_num=%x h_ret=%lli",
my_qp, qp_num, h_ret);
return ehca2ib_return_code(h_ret);
}
@@ -1261,7 +1261,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
mqpcb, my_qp->galpas.kernel);
if (h_ret != H_SUCCESS) {
ehca_err(ibqp->device, "hipz_h_query_qp() failed "
- "ehca_qp=%p qp_num=%x h_ret=%li",
+ "ehca_qp=%p qp_num=%x h_ret=%lli",
my_qp, ibqp->qp_num, h_ret);
ret = ehca2ib_return_code(h_ret);
goto modify_qp_exit1;
@@ -1690,7 +1690,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
- ehca_err(ibqp->device, "hipz_h_modify_qp() failed h_ret=%li "
+ ehca_err(ibqp->device, "hipz_h_modify_qp() failed h_ret=%lli "
"ehca_qp=%p qp_num=%x", h_ret, my_qp, ibqp->qp_num);
goto modify_qp_exit2;
}
@@ -1723,7 +1723,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
ret = ehca2ib_return_code(h_ret);
ehca_err(ibqp->device, "ENABLE in context of "
"RESET_2_INIT failed! Maybe you didn't get "
- "a LID h_ret=%li ehca_qp=%p qp_num=%x",
+ "a LID h_ret=%lli ehca_qp=%p qp_num=%x",
h_ret, my_qp, ibqp->qp_num);
goto modify_qp_exit2;
}
@@ -1909,7 +1909,7 @@ int ehca_query_qp(struct ib_qp *qp,
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
ehca_err(qp->device, "hipz_h_query_qp() failed "
- "ehca_qp=%p qp_num=%x h_ret=%li",
+ "ehca_qp=%p qp_num=%x h_ret=%lli",
my_qp, qp->qp_num, h_ret);
goto query_qp_exit1;
}
@@ -2074,7 +2074,7 @@ int ehca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
- ehca_err(ibsrq->device, "hipz_h_modify_qp() failed h_ret=%li "
+ ehca_err(ibsrq->device, "hipz_h_modify_qp() failed h_ret=%lli "
"ehca_qp=%p qp_num=%x",
h_ret, my_qp, my_qp->real_qp_num);
}
@@ -2108,7 +2108,7 @@ int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr)
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
ehca_err(srq->device, "hipz_h_query_qp() failed "
- "ehca_qp=%p qp_num=%x h_ret=%li",
+ "ehca_qp=%p qp_num=%x h_ret=%lli",
my_qp, my_qp->real_qp_num, h_ret);
goto query_srq_exit1;
}
@@ -2179,7 +2179,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
if (h_ret != H_SUCCESS) {
- ehca_err(dev, "hipz_h_destroy_qp() failed h_ret=%li "
+ ehca_err(dev, "hipz_h_destroy_qp() failed h_ret=%lli "
"ehca_qp=%p qp_num=%x", h_ret, my_qp, qp_num);
return ehca2ib_return_code(h_ret);
}
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index c7112686782f..5a3d96f84c79 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -822,7 +822,7 @@ static int generate_flush_cqes(struct ehca_qp *my_qp, struct ib_cq *cq,
offset = qmap->next_wqe_idx * ipz_queue->qe_size;
wqe = (struct ehca_wqe *)ipz_qeit_calc(ipz_queue, offset);
if (!wqe) {
- ehca_err(cq->device, "Invalid wqe offset=%#lx on "
+ ehca_err(cq->device, "Invalid wqe offset=%#llx on "
"qp_num=%#x", offset, my_qp->real_qp_num);
return nr;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c
index 706d97ad5555..44447aaa5501 100644
--- a/drivers/infiniband/hw/ehca/ehca_sqp.c
+++ b/drivers/infiniband/hw/ehca/ehca_sqp.c
@@ -85,7 +85,7 @@ u64 ehca_define_sqp(struct ehca_shca *shca,
if (ret != H_SUCCESS) {
ehca_err(&shca->ib_device,
- "Can't define AQP1 for port %x. h_ret=%li",
+ "Can't define AQP1 for port %x. h_ret=%lli",
port, ret);
return ret;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h
index 21f7d06f14ad..f09914cccf53 100644
--- a/drivers/infiniband/hw/ehca/ehca_tools.h
+++ b/drivers/infiniband/hw/ehca/ehca_tools.h
@@ -116,7 +116,7 @@ extern int ehca_debug_level;
unsigned char *deb = (unsigned char *)(adr); \
for (x = 0; x < l; x += 16) { \
printk(KERN_INFO "EHCA_DMP:%s " format \
- " adr=%p ofs=%04x %016lx %016lx\n", \
+ " adr=%p ofs=%04x %016llx %016llx\n", \
__func__, ##args, deb, x, \
*((u64 *)&deb[0]), *((u64 *)&deb[8])); \
deb += 16; \
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
index e43ed8f8a0c8..3cb688d29131 100644
--- a/drivers/infiniband/hw/ehca/ehca_uverbs.c
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -114,7 +114,7 @@ static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,
physical = galpas->user.fw_handle;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical);
+ ehca_gen_dbg("vsize=%llx physical=%llx", vsize, physical);
/* VM_IO | VM_RESERVED are set by remap_pfn_range() */
ret = remap_4k_pfn(vma, vma->vm_start, physical >> EHCA_PAGESHIFT,
vma->vm_page_prot);
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c
index 415d3a465de6..d0ab0c0d5e91 100644
--- a/drivers/infiniband/hw/ehca/hcp_if.c
+++ b/drivers/infiniband/hw/ehca/hcp_if.c
@@ -226,7 +226,7 @@ u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle,
u32 *eq_ist)
{
u64 ret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
u64 allocate_controls;
/* resource type */
@@ -249,7 +249,7 @@ u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle,
*eq_ist = (u32)outs[5];
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Not enough resource - ret=%li ", ret);
+ ehca_gen_err("Not enough resource - ret=%lli ", ret);
return ret;
}
@@ -270,7 +270,7 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
struct ehca_alloc_cq_parms *param)
{
u64 ret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
adapter_handle.handle, /* r4 */
@@ -287,7 +287,7 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]);
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Not enough resources. ret=%li", ret);
+ ehca_gen_err("Not enough resources. ret=%lli", ret);
return ret;
}
@@ -297,7 +297,7 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
{
u64 ret;
u64 allocate_controls, max_r10_reg, r11, r12;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
allocate_controls =
EHCA_BMASK_SET(H_ALL_RES_QP_ENHANCED_OPS, parms->ext_type)
@@ -362,7 +362,7 @@ u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
hcp_galpas_ctor(&parms->galpas, outs[6], outs[6]);
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Not enough resources. ret=%li", ret);
+ ehca_gen_err("Not enough resources. ret=%lli", ret);
return ret;
}
@@ -454,7 +454,7 @@ u64 hipz_h_register_rpage_eq(const struct ipz_adapter_handle adapter_handle,
const u64 count)
{
if (count != 1) {
- ehca_gen_err("Ppage counter=%lx", count);
+ ehca_gen_err("Ppage counter=%llx", count);
return H_PARAMETER;
}
return hipz_h_register_rpage(adapter_handle,
@@ -489,7 +489,7 @@ u64 hipz_h_register_rpage_cq(const struct ipz_adapter_handle adapter_handle,
const struct h_galpa gal)
{
if (count != 1) {
- ehca_gen_err("Page counter=%lx", count);
+ ehca_gen_err("Page counter=%llx", count);
return H_PARAMETER;
}
@@ -508,7 +508,7 @@ u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
const struct h_galpa galpa)
{
if (count > 1) {
- ehca_gen_err("Page counter=%lx", count);
+ ehca_gen_err("Page counter=%llx", count);
return H_PARAMETER;
}
@@ -525,7 +525,7 @@ u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
int dis_and_get_function_code)
{
u64 ret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
ret = ehca_plpar_hcall9(H_DISABLE_AND_GETC, outs,
adapter_handle.handle, /* r4 */
@@ -548,7 +548,7 @@ u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle,
struct h_galpa gal)
{
u64 ret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
ret = ehca_plpar_hcall9(H_MODIFY_QP, outs,
adapter_handle.handle, /* r4 */
qp_handle.handle, /* r5 */
@@ -557,7 +557,7 @@ u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle,
0, 0, 0, 0, 0);
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Insufficient resources ret=%li", ret);
+ ehca_gen_err("Insufficient resources ret=%lli", ret);
return ret;
}
@@ -579,7 +579,7 @@ u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
struct ehca_qp *qp)
{
u64 ret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
ret = hcp_galpas_dtor(&qp->galpas);
if (ret) {
@@ -593,7 +593,7 @@ u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
qp->ipz_qp_handle.handle, /* r6 */
0, 0, 0, 0, 0, 0);
if (ret == H_HARDWARE)
- ehca_gen_err("HCA not operational. ret=%li", ret);
+ ehca_gen_err("HCA not operational. ret=%lli", ret);
ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
adapter_handle.handle, /* r4 */
@@ -601,7 +601,7 @@ u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
0, 0, 0, 0, 0);
if (ret == H_RESOURCE)
- ehca_gen_err("Resource still in use. ret=%li", ret);
+ ehca_gen_err("Resource still in use. ret=%lli", ret);
return ret;
}
@@ -625,7 +625,7 @@ u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle,
u32 * bma_qp_nr)
{
u64 ret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
ret = ehca_plpar_hcall9(H_DEFINE_AQP1, outs,
adapter_handle.handle, /* r4 */
@@ -636,7 +636,7 @@ u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle,
*bma_qp_nr = (u32)outs[1];
if (ret == H_ALIAS_EXIST)
- ehca_gen_err("AQP1 already exists. ret=%li", ret);
+ ehca_gen_err("AQP1 already exists. ret=%lli", ret);
return ret;
}
@@ -658,7 +658,7 @@ u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle,
0, 0);
if (ret == H_NOT_ENOUGH_RESOURCES)
- ehca_gen_err("Not enough resources. ret=%li", ret);
+ ehca_gen_err("Not enough resources. ret=%lli", ret);
return ret;
}
@@ -697,7 +697,7 @@ u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle,
0, 0, 0, 0);
if (ret == H_RESOURCE)
- ehca_gen_err("H_FREE_RESOURCE failed ret=%li ", ret);
+ ehca_gen_err("H_FREE_RESOURCE failed ret=%lli ", ret);
return ret;
}
@@ -719,7 +719,7 @@ u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle,
0, 0, 0, 0, 0);
if (ret == H_RESOURCE)
- ehca_gen_err("Resource in use. ret=%li ", ret);
+ ehca_gen_err("Resource in use. ret=%lli ", ret);
return ret;
}
@@ -733,7 +733,7 @@ u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle,
struct ehca_mr_hipzout_parms *outparms)
{
u64 ret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
adapter_handle.handle, /* r4 */
@@ -774,9 +774,9 @@ u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle,
if ((count > 1) && (logical_address_of_page & (EHCA_PAGESIZE-1))) {
ehca_gen_err("logical_address_of_page not on a 4k boundary "
- "adapter_handle=%lx mr=%p mr_handle=%lx "
+ "adapter_handle=%llx mr=%p mr_handle=%llx "
"pagesize=%x queue_type=%x "
- "logical_address_of_page=%lx count=%lx",
+ "logical_address_of_page=%llx count=%llx",
adapter_handle.handle, mr,
mr->ipz_mr_handle.handle, pagesize, queue_type,
logical_address_of_page, count);
@@ -794,7 +794,7 @@ u64 hipz_h_query_mr(const struct ipz_adapter_handle adapter_handle,
struct ehca_mr_hipzout_parms *outparms)
{
u64 ret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
ret = ehca_plpar_hcall9(H_QUERY_MR, outs,
adapter_handle.handle, /* r4 */
@@ -828,7 +828,7 @@ u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle,
struct ehca_mr_hipzout_parms *outparms)
{
u64 ret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
ret = ehca_plpar_hcall9(H_REREGISTER_PMR, outs,
adapter_handle.handle, /* r4 */
@@ -855,7 +855,7 @@ u64 hipz_h_register_smr(const struct ipz_adapter_handle adapter_handle,
struct ehca_mr_hipzout_parms *outparms)
{
u64 ret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
ret = ehca_plpar_hcall9(H_REGISTER_SMR, outs,
adapter_handle.handle, /* r4 */
@@ -877,7 +877,7 @@ u64 hipz_h_alloc_resource_mw(const struct ipz_adapter_handle adapter_handle,
struct ehca_mw_hipzout_parms *outparms)
{
u64 ret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
adapter_handle.handle, /* r4 */
@@ -895,7 +895,7 @@ u64 hipz_h_query_mw(const struct ipz_adapter_handle adapter_handle,
struct ehca_mw_hipzout_parms *outparms)
{
u64 ret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
ret = ehca_plpar_hcall9(H_QUERY_MW, outs,
adapter_handle.handle, /* r4 */
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index a3c5af1d7ec0..de5263beab4a 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -367,7 +367,7 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
if (err)
goto out;
} else {
- /* Can't be smaller then the number of outstanding CQEs */
+ /* Can't be smaller than the number of outstanding CQEs */
outst_cqe = mlx4_ib_get_outstanding_cqes(cq);
if (entries < outst_cqe + 1) {
err = 0;
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index dcefe1fceb5c..61588bd273bd 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -543,14 +543,21 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
{
static int mlx4_ib_version_printed;
struct mlx4_ib_dev *ibdev;
+ int num_ports = 0;
int i;
-
if (!mlx4_ib_version_printed) {
printk(KERN_INFO "%s", mlx4_ib_version);
++mlx4_ib_version_printed;
}
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
+ num_ports++;
+
+ /* No point in registering a device with no ports... */
+ if (num_ports == 0)
+ return NULL;
+
ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev);
if (!ibdev) {
dev_err(&dev->pdev->dev, "Device struct alloc failed\n");
@@ -574,9 +581,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev->ib_dev.owner = THIS_MODULE;
ibdev->ib_dev.node_type = RDMA_NODE_IB_CA;
ibdev->ib_dev.local_dma_lkey = dev->caps.reserved_lkey;
- ibdev->num_ports = 0;
- mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
- ibdev->num_ports++;
+ ibdev->num_ports = num_ports;
ibdev->ib_dev.phys_port_cnt = ibdev->num_ports;
ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors;
ibdev->ib_dev.dma_device = &dev->pdev->dev;
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 39167a797f99..a91cb4c3fa5c 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -1462,7 +1462,8 @@ static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg)
}
static int build_lso_seg(struct mlx4_wqe_lso_seg *wqe, struct ib_send_wr *wr,
- struct mlx4_ib_qp *qp, unsigned *lso_seg_len)
+ struct mlx4_ib_qp *qp, unsigned *lso_seg_len,
+ __be32 *lso_hdr_sz)
{
unsigned halign = ALIGN(sizeof *wqe + wr->wr.ud.hlen, 16);
@@ -1479,12 +1480,8 @@ static int build_lso_seg(struct mlx4_wqe_lso_seg *wqe, struct ib_send_wr *wr,
memcpy(wqe->header, wr->wr.ud.header, wr->wr.ud.hlen);
- /* make sure LSO header is written before overwriting stamping */
- wmb();
-
- wqe->mss_hdr_size = cpu_to_be32((wr->wr.ud.mss - wr->wr.ud.hlen) << 16 |
- wr->wr.ud.hlen);
-
+ *lso_hdr_sz = cpu_to_be32((wr->wr.ud.mss - wr->wr.ud.hlen) << 16 |
+ wr->wr.ud.hlen);
*lso_seg_len = halign;
return 0;
}
@@ -1518,6 +1515,9 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
int uninitialized_var(stamp);
int uninitialized_var(size);
unsigned uninitialized_var(seglen);
+ __be32 dummy;
+ __be32 *lso_wqe;
+ __be32 uninitialized_var(lso_hdr_sz);
int i;
spin_lock_irqsave(&qp->sq.lock, flags);
@@ -1525,6 +1525,8 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
ind = qp->sq_next_wqe;
for (nreq = 0; wr; ++nreq, wr = wr->next) {
+ lso_wqe = &dummy;
+
if (mlx4_wq_overflow(&qp->sq, nreq, qp->ibqp.send_cq)) {
err = -ENOMEM;
*bad_wr = wr;
@@ -1606,11 +1608,12 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
if (wr->opcode == IB_WR_LSO) {
- err = build_lso_seg(wqe, wr, qp, &seglen);
+ err = build_lso_seg(wqe, wr, qp, &seglen, &lso_hdr_sz);
if (unlikely(err)) {
*bad_wr = wr;
goto out;
}
+ lso_wqe = (__be32 *) wqe;
wqe += seglen;
size += seglen / 16;
}
@@ -1652,6 +1655,14 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
for (i = wr->num_sge - 1; i >= 0; --i, --dseg)
set_data_seg(dseg, wr->sg_list + i);
+ /*
+ * Possibly overwrite stamping in cacheline with LSO
+ * segment only after making sure all data segments
+ * are written.
+ */
+ wmb();
+ *lso_wqe = lso_hdr_sz;
+
ctrl->fence_size = (wr->send_flags & IB_SEND_FENCE ?
MLX4_WQE_CTRL_FENCE : 0) | size;
@@ -1686,7 +1697,6 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
stamp_send_wqe(qp, stamp, size * 16);
ind = pad_wraparound(qp, ind);
}
-
}
out:
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index a812db243477..a01b4488208b 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -778,12 +778,13 @@ static struct nes_cm_node *find_node(struct nes_cm_core *cm_core,
unsigned long flags;
struct list_head *hte;
struct nes_cm_node *cm_node;
+ __be32 tmp_addr = cpu_to_be32(loc_addr);
/* get a handle on the hte */
hte = &cm_core->connected_nodes;
nes_debug(NES_DBG_CM, "Searching for an owner node: %pI4:%x from core %p->%p\n",
- &loc_addr, loc_port, cm_core, hte);
+ &tmp_addr, loc_port, cm_core, hte);
/* walk list and find cm_node associated with this session ID */
spin_lock_irqsave(&cm_core->ht_lock, flags);
@@ -816,6 +817,7 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
{
unsigned long flags;
struct nes_cm_listener *listen_node;
+ __be32 tmp_addr = cpu_to_be32(dst_addr);
/* walk list and find cm_node associated with this session ID */
spin_lock_irqsave(&cm_core->listen_list_lock, flags);
@@ -833,7 +835,7 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core,
spin_unlock_irqrestore(&cm_core->listen_list_lock, flags);
nes_debug(NES_DBG_CM, "Unable to find listener for %pI4:%x\n",
- &dst_addr, dst_port);
+ &tmp_addr, dst_port);
/* no listener */
return NULL;
@@ -2059,6 +2061,7 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
struct tcphdr *tcph;
struct nes_cm_info nfo;
int skb_handled = 1;
+ __be32 tmp_daddr, tmp_saddr;
if (!skb)
return 0;
@@ -2074,8 +2077,11 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core,
nfo.rem_addr = ntohl(iph->saddr);
nfo.rem_port = ntohs(tcph->source);
+ tmp_daddr = cpu_to_be32(iph->daddr);
+ tmp_saddr = cpu_to_be32(iph->saddr);
+
nes_debug(NES_DBG_CM, "Received packet: dest=%pI4:0x%04X src=%pI4:0x%04X\n",
- &iph->daddr, tcph->dest, &iph->saddr, tcph->source);
+ &tmp_daddr, tcph->dest, &tmp_saddr, tcph->source);
do {
cm_node = find_node(cm_core,
@@ -2705,7 +2711,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
sizeof(struct ietf_mpa_frame));
- /* notify OF layer that accept event was successfull */
+ /* notify OF layer that accept event was successful */
cm_id->add_ref(cm_id);
cm_event.event = IW_CM_EVENT_ESTABLISHED;
diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c
index aa9b7348c728..6f3bc1b6bf22 100644
--- a/drivers/infiniband/hw/nes/nes_utils.c
+++ b/drivers/infiniband/hw/nes/nes_utils.c
@@ -655,6 +655,7 @@ int nes_arp_table(struct nes_device *nesdev, u32 ip_addr, u8 *mac_addr, u32 acti
struct nes_adapter *nesadapter = nesdev->nesadapter;
int arp_index;
int err = 0;
+ __be32 tmp_addr;
for (arp_index = 0; (u32) arp_index < nesadapter->arp_table_size; arp_index++) {
if (nesadapter->arp_table[arp_index].ip_addr == ip_addr)
@@ -682,8 +683,9 @@ int nes_arp_table(struct nes_device *nesdev, u32 ip_addr, u8 *mac_addr, u32 acti
/* DELETE or RESOLVE */
if (arp_index == nesadapter->arp_table_size) {
+ tmp_addr = cpu_to_be32(ip_addr);
nes_debug(NES_DBG_NETDEV, "MAC for %pI4 not in ARP table - cannot %s\n",
- &ip_addr, action == NES_ARP_RESOLVE ? "resolve" : "delete");
+ &tmp_addr, action == NES_ARP_RESOLVE ? "resolve" : "delete");
return -1;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 19e06bc38b39..0bd2a4ff0842 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -106,23 +106,17 @@ int ipoib_open(struct net_device *dev)
ipoib_dbg(priv, "bringing up interface\n");
- set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
+ if (!test_and_set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
+ napi_enable(&priv->napi);
if (ipoib_pkey_dev_delay_open(dev))
return 0;
- napi_enable(&priv->napi);
+ if (ipoib_ib_dev_open(dev))
+ goto err_disable;
- if (ipoib_ib_dev_open(dev)) {
- napi_disable(&priv->napi);
- return -EINVAL;
- }
-
- if (ipoib_ib_dev_up(dev)) {
- ipoib_ib_dev_stop(dev, 1);
- napi_disable(&priv->napi);
- return -EINVAL;
- }
+ if (ipoib_ib_dev_up(dev))
+ goto err_stop;
if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
struct ipoib_dev_priv *cpriv;
@@ -144,6 +138,15 @@ int ipoib_open(struct net_device *dev)
netif_start_queue(dev);
return 0;
+
+err_stop:
+ ipoib_ib_dev_stop(dev, 1);
+
+err_disable:
+ napi_disable(&priv->napi);
+ clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
+
+ return -EINVAL;
}
static int ipoib_stop(struct net_device *dev)
@@ -711,26 +714,26 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
neigh = *to_ipoib_neigh(skb->dst->neighbour);
- if (neigh->ah)
- if (unlikely((memcmp(&neigh->dgid.raw,
- skb->dst->neighbour->ha + 4,
- sizeof(union ib_gid))) ||
- (neigh->dev != dev))) {
- spin_lock_irqsave(&priv->lock, flags);
- /*
- * It's safe to call ipoib_put_ah() inside
- * priv->lock here, because we know that
- * path->ah will always hold one more reference,
- * so ipoib_put_ah() will never do more than
- * decrement the ref count.
- */
+ if (unlikely((memcmp(&neigh->dgid.raw,
+ skb->dst->neighbour->ha + 4,
+ sizeof(union ib_gid))) ||
+ (neigh->dev != dev))) {
+ spin_lock_irqsave(&priv->lock, flags);
+ /*
+ * It's safe to call ipoib_put_ah() inside
+ * priv->lock here, because we know that
+ * path->ah will always hold one more reference,
+ * so ipoib_put_ah() will never do more than
+ * decrement the ref count.
+ */
+ if (neigh->ah)
ipoib_put_ah(neigh->ah);
- list_del(&neigh->list);
- ipoib_neigh_free(dev, neigh);
- spin_unlock_irqrestore(&priv->lock, flags);
- ipoib_path_lookup(skb, dev);
- return NETDEV_TX_OK;
- }
+ list_del(&neigh->list);
+ ipoib_neigh_free(dev, neigh);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ ipoib_path_lookup(skb, dev);
+ return NETDEV_TX_OK;
+ }
if (ipoib_cm_get(neigh)) {
if (ipoib_cm_up(neigh)) {
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index a2eb3b9789eb..425e31112ed7 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -409,7 +409,7 @@ static int ipoib_mcast_join_complete(int status,
}
if (mcast->logcount++ < 20) {
- if (status == -ETIMEDOUT) {
+ if (status == -ETIMEDOUT || status == -EAGAIN) {
ipoib_dbg_mcast(priv, "multicast join failed for %pI6, status %d\n",
mcast->mcmember.mgid.raw, status);
} else {
@@ -529,6 +529,9 @@ void ipoib_mcast_join_task(struct work_struct *work)
if (!priv->broadcast) {
struct ipoib_mcast *broadcast;
+ if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
+ return;
+
broadcast = ipoib_mcast_alloc(dev, 1);
if (!broadcast) {
ipoib_warn(priv, "failed to allocate broadcast group\n");
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 2cf1a4088718..5a76a5510350 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -61,6 +61,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
ppriv = netdev_priv(pdev);
+ rtnl_lock();
mutex_lock(&ppriv->vlan_mutex);
/*
@@ -111,7 +112,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
goto device_init_failed;
}
- result = register_netdev(priv->dev);
+ result = register_netdevice(priv->dev);
if (result) {
ipoib_warn(priv, "failed to initialize; error %i", result);
goto register_failed;
@@ -134,12 +135,13 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
list_add_tail(&priv->list, &ppriv->child_intfs);
mutex_unlock(&ppriv->vlan_mutex);
+ rtnl_unlock();
return 0;
sysfs_failed:
ipoib_delete_debug_files(priv->dev);
- unregister_netdev(priv->dev);
+ unregister_netdevice(priv->dev);
register_failed:
ipoib_dev_cleanup(priv->dev);
@@ -149,6 +151,7 @@ device_init_failed:
err:
mutex_unlock(&ppriv->vlan_mutex);
+ rtnl_unlock();
return result;
}
@@ -162,10 +165,11 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
ppriv = netdev_priv(pdev);
+ rtnl_lock();
mutex_lock(&ppriv->vlan_mutex);
list_for_each_entry_safe(priv, tpriv, &ppriv->child_intfs, list) {
if (priv->pkey == pkey) {
- unregister_netdev(priv->dev);
+ unregister_netdevice(priv->dev);
ipoib_dev_cleanup(priv->dev);
list_del(&priv->list);
free_netdev(priv->dev);
@@ -175,6 +179,7 @@ int ipoib_vlan_delete(struct net_device *pdev, unsigned short pkey)
}
}
mutex_unlock(&ppriv->vlan_mutex);
+ rtnl_unlock();
return ret;
}
diff --git a/drivers/infiniband/ulp/iser/Kconfig b/drivers/infiniband/ulp/iser/Kconfig
index 77dedba829e6..b411c51842da 100644
--- a/drivers/infiniband/ulp/iser/Kconfig
+++ b/drivers/infiniband/ulp/iser/Kconfig
@@ -1,6 +1,6 @@
config INFINIBAND_ISER
tristate "iSCSI Extensions for RDMA (iSER)"
- depends on SCSI && INET
+ depends on SCSI && INET && INFINIBAND_ADDR_TRANS
select SCSI_ISCSI_ATTRS
---help---
Support for the iSCSI Extensions for RDMA (iSER) Protocol
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index f6e9f39a527b..c3c8b9bc40ae 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -65,7 +65,7 @@ MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and
/*
* Scancode to keycode tables. These are just the default setting, and
- * are loadable via an userland utility.
+ * are loadable via a userland utility.
*/
static const unsigned short atkbd_set2_keycode[512] = {
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 199055db5082..67e5553f699a 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -220,4 +220,11 @@ config HP_SDC_RTC
Say Y here if you want to support the built-in real time clock
of the HP SDC controller.
+config INPUT_PCF50633_PMU
+ tristate "PCF50633 PMU events"
+ depends on MFD_PCF50633
+ help
+ Say Y to include support for delivering PMU events via input
+ layer on NXP PCF50633.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index d7db2aeb8a98..bb62e6efacf3 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -21,3 +21,4 @@ obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_APANEL) += apanel.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
+obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c
index d82f7f727f7a..71b82434264d 100644
--- a/drivers/input/misc/apanel.c
+++ b/drivers/input/misc/apanel.c
@@ -57,7 +57,7 @@ static enum apanel_chip device_chip[APANEL_DEV_MAX];
struct apanel {
struct input_polled_dev *ipdev;
- struct i2c_client client;
+ struct i2c_client *client;
unsigned short keymap[MAX_PANEL_KEYS];
u16 nkeys;
u16 led_bits;
@@ -66,16 +66,7 @@ struct apanel {
};
-static int apanel_probe(struct i2c_adapter *, int, int);
-
-/* for now, we only support one address */
-static unsigned short normal_i2c[] = {0, I2C_CLIENT_END};
-static unsigned short ignore = I2C_CLIENT_END;
-static struct i2c_client_address_data addr_data = {
- .normal_i2c = normal_i2c,
- .probe = &ignore,
- .ignore = &ignore,
-};
+static int apanel_probe(struct i2c_client *, const struct i2c_device_id *);
static void report_key(struct input_dev *input, unsigned keycode)
{
@@ -103,12 +94,12 @@ static void apanel_poll(struct input_polled_dev *ipdev)
s32 data;
int i;
- data = i2c_smbus_read_word_data(&ap->client, cmd);
+ data = i2c_smbus_read_word_data(ap->client, cmd);
if (data < 0)
return; /* ignore errors (due to ACPI??) */
/* write back to clear latch */
- i2c_smbus_write_word_data(&ap->client, cmd, 0);
+ i2c_smbus_write_word_data(ap->client, cmd, 0);
if (!data)
return;
@@ -124,7 +115,7 @@ static void led_update(struct work_struct *work)
{
struct apanel *ap = container_of(work, struct apanel, led_work);
- i2c_smbus_write_word_data(&ap->client, 0x10, ap->led_bits);
+ i2c_smbus_write_word_data(ap->client, 0x10, ap->led_bits);
}
static void mail_led_set(struct led_classdev *led,
@@ -140,7 +131,7 @@ static void mail_led_set(struct led_classdev *led,
schedule_work(&ap->led_work);
}
-static int apanel_detach_client(struct i2c_client *client)
+static int apanel_remove(struct i2c_client *client)
{
struct apanel *ap = i2c_get_clientdata(client);
@@ -148,43 +139,33 @@ static int apanel_detach_client(struct i2c_client *client)
led_classdev_unregister(&ap->mail_led);
input_unregister_polled_device(ap->ipdev);
- i2c_detach_client(&ap->client);
input_free_polled_device(ap->ipdev);
return 0;
}
-/* Function is invoked for every i2c adapter. */
-static int apanel_attach_adapter(struct i2c_adapter *adap)
-{
- dev_dbg(&adap->dev, APANEL ": attach adapter id=%d\n", adap->id);
-
- /* Our device is connected only to i801 on laptop */
- if (adap->id != I2C_HW_SMBUS_I801)
- return -ENODEV;
-
- return i2c_probe(adap, &addr_data, apanel_probe);
-}
-
static void apanel_shutdown(struct i2c_client *client)
{
- apanel_detach_client(client);
+ apanel_remove(client);
}
+static struct i2c_device_id apanel_id[] = {
+ { "fujitsu_apanel", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, apanel_id);
+
static struct i2c_driver apanel_driver = {
.driver = {
.name = APANEL,
},
- .attach_adapter = &apanel_attach_adapter,
- .detach_client = &apanel_detach_client,
+ .probe = &apanel_probe,
+ .remove = &apanel_remove,
.shutdown = &apanel_shutdown,
+ .id_table = apanel_id,
};
static struct apanel apanel = {
- .client = {
- .driver = &apanel_driver,
- .name = APANEL,
- },
.keymap = {
[0] = KEY_MAIL,
[1] = KEY_WWW,
@@ -204,7 +185,8 @@ static struct apanel apanel = {
};
/* NB: Only one panel on the i2c. */
-static int apanel_probe(struct i2c_adapter *bus, int address, int kind)
+static int apanel_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct apanel *ap;
struct input_polled_dev *ipdev;
@@ -212,9 +194,6 @@ static int apanel_probe(struct i2c_adapter *bus, int address, int kind)
u8 cmd = device_chip[APANEL_DEV_APPBTN] == CHIP_OZ992C ? 0 : 8;
int i, err = -ENOMEM;
- dev_dbg(&bus->dev, APANEL ": probe adapter %p addr %d kind %d\n",
- bus, address, kind);
-
ap = &apanel;
ipdev = input_allocate_polled_device();
@@ -222,18 +201,13 @@ static int apanel_probe(struct i2c_adapter *bus, int address, int kind)
goto out1;
ap->ipdev = ipdev;
- ap->client.adapter = bus;
- ap->client.addr = address;
-
- i2c_set_clientdata(&ap->client, ap);
+ ap->client = client;
- err = i2c_attach_client(&ap->client);
- if (err)
- goto out2;
+ i2c_set_clientdata(client, ap);
- err = i2c_smbus_write_word_data(&ap->client, cmd, 0);
+ err = i2c_smbus_write_word_data(client, cmd, 0);
if (err) {
- dev_warn(&ap->client.dev, APANEL ": smbus write error %d\n",
+ dev_warn(&client->dev, APANEL ": smbus write error %d\n",
err);
goto out3;
}
@@ -246,7 +220,7 @@ static int apanel_probe(struct i2c_adapter *bus, int address, int kind)
idev->name = APANEL_NAME " buttons";
idev->phys = "apanel/input0";
idev->id.bustype = BUS_HOST;
- idev->dev.parent = &ap->client.dev;
+ idev->dev.parent = &client->dev;
set_bit(EV_KEY, idev->evbit);
@@ -264,7 +238,7 @@ static int apanel_probe(struct i2c_adapter *bus, int address, int kind)
INIT_WORK(&ap->led_work, led_update);
if (device_chip[APANEL_DEV_LED] != CHIP_NONE) {
- err = led_classdev_register(&ap->client.dev, &ap->mail_led);
+ err = led_classdev_register(&client->dev, &ap->mail_led);
if (err)
goto out4;
}
@@ -273,8 +247,6 @@ static int apanel_probe(struct i2c_adapter *bus, int address, int kind)
out4:
input_unregister_polled_device(ipdev);
out3:
- i2c_detach_client(&ap->client);
-out2:
input_free_polled_device(ipdev);
out1:
return err;
@@ -301,6 +273,7 @@ static int __init apanel_init(void)
void __iomem *bios;
const void __iomem *p;
u8 devno;
+ unsigned char i2c_addr;
int found = 0;
bios = ioremap(0xF0000, 0x10000); /* Can't fail */
@@ -313,7 +286,7 @@ static int __init apanel_init(void)
/* just use the first address */
p += 8;
- normal_i2c[0] = readb(p+3) >> 1;
+ i2c_addr = readb(p + 3) >> 1;
for ( ; (devno = readb(p)) & 0x7f; p += 4) {
unsigned char method, slave, chip;
@@ -322,7 +295,7 @@ static int __init apanel_init(void)
chip = readb(p + 2);
slave = readb(p + 3) >> 1;
- if (slave != normal_i2c[0]) {
+ if (slave != i2c_addr) {
pr_notice(APANEL ": only one SMBus slave "
"address supported, skiping device...\n");
continue;
diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c
new file mode 100644
index 000000000000..039dcb00ebd9
--- /dev/null
+++ b/drivers/input/misc/pcf50633-input.c
@@ -0,0 +1,132 @@
+/* NXP PCF50633 Input Driver
+ *
+ * (C) 2006-2008 by Openmoko, Inc.
+ * Author: Balaji Rao <balajirrao@openmoko.org>
+ * All rights reserved.
+ *
+ * Broken down from monstrous PCF50633 driver mainly by
+ * Harald Welte, Andy Green and Werner Almesberger
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+
+#include <linux/mfd/pcf50633/core.h>
+
+#define PCF50633_OOCSTAT_ONKEY 0x01
+#define PCF50633_REG_OOCSTAT 0x12
+#define PCF50633_REG_OOCMODE 0x10
+
+struct pcf50633_input {
+ struct pcf50633 *pcf;
+ struct input_dev *input_dev;
+};
+
+static void
+pcf50633_input_irq(int irq, void *data)
+{
+ struct pcf50633_input *input;
+ int onkey_released;
+
+ input = data;
+
+ /* We report only one event depending on the key press status */
+ onkey_released = pcf50633_reg_read(input->pcf, PCF50633_REG_OOCSTAT)
+ & PCF50633_OOCSTAT_ONKEY;
+
+ if (irq == PCF50633_IRQ_ONKEYF && !onkey_released)
+ input_report_key(input->input_dev, KEY_POWER, 1);
+ else if (irq == PCF50633_IRQ_ONKEYR && onkey_released)
+ input_report_key(input->input_dev, KEY_POWER, 0);
+
+ input_sync(input->input_dev);
+}
+
+static int __devinit pcf50633_input_probe(struct platform_device *pdev)
+{
+ struct pcf50633_input *input;
+ struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
+ struct input_dev *input_dev;
+ int ret;
+
+
+ input = kzalloc(sizeof(*input), GFP_KERNEL);
+ if (!input)
+ return -ENOMEM;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ kfree(input);
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, input);
+ input->pcf = pdata->pcf;
+ input->input_dev = input_dev;
+
+ input_dev->name = "PCF50633 PMU events";
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_PWR);
+ set_bit(KEY_POWER, input_dev->keybit);
+
+ ret = input_register_device(input_dev);
+ if (ret) {
+ input_free_device(input_dev);
+ kfree(input);
+ return ret;
+ }
+ pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYR,
+ pcf50633_input_irq, input);
+ pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYF,
+ pcf50633_input_irq, input);
+
+ return 0;
+}
+
+static int __devexit pcf50633_input_remove(struct platform_device *pdev)
+{
+ struct pcf50633_input *input = platform_get_drvdata(pdev);
+
+ pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYR);
+ pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYF);
+
+ input_unregister_device(input->input_dev);
+ kfree(input);
+
+ return 0;
+}
+
+static struct platform_driver pcf50633_input_driver = {
+ .driver = {
+ .name = "pcf50633-input",
+ },
+ .probe = pcf50633_input_probe,
+ .remove = __devexit_p(pcf50633_input_remove),
+};
+
+static int __init pcf50633_input_init(void)
+{
+ return platform_driver_register(&pcf50633_input_driver);
+}
+module_init(pcf50633_input_init);
+
+static void __exit pcf50633_input_exit(void)
+{
+ platform_driver_unregister(&pcf50633_input_driver);
+}
+module_exit(pcf50633_input_exit);
+
+MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
+MODULE_DESCRIPTION("PCF50633 input driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcf50633-input");
diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c
index a0f45c4fc198..d297accf9a7f 100644
--- a/drivers/input/mouse/pxa930_trkball.c
+++ b/drivers/input/mouse/pxa930_trkball.c
@@ -186,7 +186,7 @@ static int __devinit pxa930_trkball_probe(struct platform_device *pdev)
error = request_irq(irq, pxa930_trkball_interrupt, IRQF_DISABLED,
pdev->name, trkball);
if (error) {
- dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+ dev_err(&pdev->dev, "failed to request irq: %d\n", error);
goto failed_free_io;
}
@@ -227,7 +227,7 @@ failed_free_io:
iounmap(trkball->mmio_base);
failed:
kfree(trkball);
- return ret;
+ return error;
}
static int __devexit pxa930_trkball_remove(struct platform_device *pdev)
diff --git a/drivers/input/touchscreen/da9034-ts.c b/drivers/input/touchscreen/da9034-ts.c
index 4342e77814b5..fa67d782c3c3 100644
--- a/drivers/input/touchscreen/da9034-ts.c
+++ b/drivers/input/touchscreen/da9034-ts.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
+#include <linux/workqueue.h>
#include <linux/mfd/da903x.h>
#define DA9034_MANUAL_CTRL 0x50
diff --git a/drivers/isdn/hardware/eicon/debuglib.h b/drivers/isdn/hardware/eicon/debuglib.h
index 016410cf2273..8ea587783e14 100644
--- a/drivers/isdn/hardware/eicon/debuglib.h
+++ b/drivers/isdn/hardware/eicon/debuglib.h
@@ -235,7 +235,7 @@ typedef void ( * DbgOld) (unsigned short, char *, va_list) ;
typedef void ( * DbgEv) (unsigned short, unsigned long, va_list) ;
typedef void ( * DbgIrq) (unsigned short, int, char *, va_list) ;
typedef struct _DbgHandle_
-{ char Registered ; /* driver successfull registered */
+{ char Registered ; /* driver successfully registered */
#define DBG_HANDLE_REG_NEW 0x01 /* this (new) structure */
#define DBG_HANDLE_REG_OLD 0x7f /* old structure (see below) */
char Version; /* version of this structure */
diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c
index 7b4ec3f60dbf..c964b8d91ada 100644
--- a/drivers/isdn/hardware/eicon/os_4bri.c
+++ b/drivers/isdn/hardware/eicon/os_4bri.c
@@ -997,7 +997,7 @@ diva_4bri_start_adapter(PISDN_ADAPTER IoAdapter,
diva_xdi_display_adapter_features(IoAdapter->ANum);
for (i = 0; i < IoAdapter->tasks; i++) {
- DBG_LOG(("A(%d) %s adapter successfull started",
+ DBG_LOG(("A(%d) %s adapter successfully started",
IoAdapter->QuadroList->QuadroAdapter[i]->ANum,
(IoAdapter->tasks == 1) ? "BRI 2.0" : "4BRI"))
diva_xdi_didd_register_adapter(IoAdapter->QuadroList->QuadroAdapter[i]->ANum);
diff --git a/drivers/isdn/hardware/eicon/os_bri.c b/drivers/isdn/hardware/eicon/os_bri.c
index f31bba5b16ff..08f01993f46b 100644
--- a/drivers/isdn/hardware/eicon/os_bri.c
+++ b/drivers/isdn/hardware/eicon/os_bri.c
@@ -736,7 +736,7 @@ diva_bri_start_adapter(PISDN_ADAPTER IoAdapter,
IoAdapter->Properties.Features = (word) features;
diva_xdi_display_adapter_features(IoAdapter->ANum);
- DBG_LOG(("A(%d) BRI adapter successfull started", IoAdapter->ANum))
+ DBG_LOG(("A(%d) BRI adapter successfully started", IoAdapter->ANum))
/*
Register with DIDD
*/
diff --git a/drivers/isdn/hardware/eicon/os_pri.c b/drivers/isdn/hardware/eicon/os_pri.c
index 903356547b79..5d65405c75f4 100644
--- a/drivers/isdn/hardware/eicon/os_pri.c
+++ b/drivers/isdn/hardware/eicon/os_pri.c
@@ -513,7 +513,7 @@ diva_pri_start_adapter(PISDN_ADAPTER IoAdapter,
diva_xdi_display_adapter_features(IoAdapter->ANum);
- DBG_LOG(("A(%d) PRI adapter successfull started", IoAdapter->ANum))
+ DBG_LOG(("A(%d) PRI adapter successfully started", IoAdapter->ANum))
/*
Register with DIDD
*/
diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig
index 14793480c453..fd112ae252cf 100644
--- a/drivers/isdn/hardware/mISDN/Kconfig
+++ b/drivers/isdn/hardware/mISDN/Kconfig
@@ -23,3 +23,10 @@ config MISDN_HFCMULTI
* HFC-8S (8 S/T interfaces on one chip)
* HFC-E1 (E1 interface for 2Mbit ISDN)
+config MISDN_HFCUSB
+ tristate "Support for HFC-S USB based TAs"
+ depends on USB
+ help
+ Enable support for USB ISDN TAs with Cologne Chip AG's
+ HFC-S USB ISDN Controller
+
diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile
index 1e7ca5332ad7..b0403526bbba 100644
--- a/drivers/isdn/hardware/mISDN/Makefile
+++ b/drivers/isdn/hardware/mISDN/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o
obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o
+obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o
diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h
index 7bbf7300593d..663b77f578be 100644
--- a/drivers/isdn/hardware/mISDN/hfc_multi.h
+++ b/drivers/isdn/hardware/mISDN/hfc_multi.h
@@ -2,10 +2,6 @@
* see notice in hfc_multi.c
*/
-extern void ztdummy_extern_interrupt(void);
-extern void ztdummy_register_interrupt(void);
-extern int ztdummy_unregister_interrupt(void);
-
#define DEBUG_HFCMULTI_FIFO 0x00010000
#define DEBUG_HFCMULTI_CRC 0x00020000
#define DEBUG_HFCMULTI_INIT 0x00040000
@@ -13,6 +9,7 @@ extern int ztdummy_unregister_interrupt(void);
#define DEBUG_HFCMULTI_MODE 0x00100000
#define DEBUG_HFCMULTI_MSG 0x00200000
#define DEBUG_HFCMULTI_STATE 0x00400000
+#define DEBUG_HFCMULTI_FILL 0x00800000
#define DEBUG_HFCMULTI_SYNC 0x01000000
#define DEBUG_HFCMULTI_DTMF 0x02000000
#define DEBUG_HFCMULTI_LOCK 0x80000000
@@ -170,6 +167,8 @@ struct hfc_multi {
u_long chip; /* chip configuration */
int masterclk; /* port that provides master clock -1=off */
+ unsigned char silence;/* silence byte */
+ unsigned char silence_data[128];/* silence block */
int dtmf; /* flag that dtmf is currently in process */
int Flen; /* F-buffer size */
int Zlen; /* Z-buffer size (must be int for calculation)*/
@@ -198,6 +197,9 @@ struct hfc_multi {
spinlock_t lock; /* the lock */
+ struct mISDNclock *iclock; /* isdn clock support */
+ int iclock_on;
+
/*
* the channel index is counted from 0, regardless where the channel
* is located on the hfc-channel.
diff --git a/drivers/isdn/hardware/mISDN/hfc_pci.h b/drivers/isdn/hardware/mISDN/hfc_pci.h
index 5783d22a18fe..3132ddc99fcd 100644
--- a/drivers/isdn/hardware/mISDN/hfc_pci.h
+++ b/drivers/isdn/hardware/mISDN/hfc_pci.h
@@ -26,7 +26,7 @@
* change mask and threshold simultaneously
*/
#define HFCPCI_BTRANS_THRESHOLD 128
-#define HFCPCI_BTRANS_MAX 256
+#define HFCPCI_FILLEMPTY 64
#define HFCPCI_BTRANS_THRESMASK 0x00
/* defines for PCI config */
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index c63e2f49da8a..595ba8eb4a07 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -133,6 +133,12 @@
* Give the value of the clock control register (A_ST_CLK_DLY)
* of the S/T interfaces in TE mode.
* This register is needed for the TBR3 certification, so don't change it.
+ *
+ * clock:
+ * NOTE: only one clock value must be given once
+ * Selects interface with clock source for mISDN and applications.
+ * Set to card number starting with 1. Set to -1 to disable.
+ * By default, the first card is used as clock source.
*/
/*
@@ -140,7 +146,7 @@
* #define HFC_REGISTER_DEBUG
*/
-static const char *hfcmulti_revision = "2.02";
+#define HFC_MULTI_VERSION "2.03"
#include <linux/module.h>
#include <linux/pci.h>
@@ -165,10 +171,6 @@ static LIST_HEAD(HFClist);
static spinlock_t HFClock; /* global hfc list lock */
static void ph_state_change(struct dchannel *);
-static void (*hfc_interrupt)(void);
-static void (*register_interrupt)(void);
-static int (*unregister_interrupt)(void);
-static int interrupt_registered;
static struct hfc_multi *syncmaster;
static int plxsd_master; /* if we have a master card (yet) */
@@ -184,7 +186,6 @@ static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 };
#define CLKDEL_TE 0x0f /* CLKDEL in TE mode */
#define CLKDEL_NT 0x6c /* CLKDEL in NT mode
(0x60 MUST be included!) */
-static u_char silence = 0xff; /* silence by LAW */
#define DIP_4S 0x1 /* DIP Switches for Beronet 1S/2S/4S cards */
#define DIP_8S 0x2 /* DIP Switches for Beronet 8S+ cards */
@@ -195,12 +196,13 @@ static u_char silence = 0xff; /* silence by LAW */
*/
static uint type[MAX_CARDS];
-static uint pcm[MAX_CARDS];
-static uint dslot[MAX_CARDS];
+static int pcm[MAX_CARDS];
+static int dslot[MAX_CARDS];
static uint iomode[MAX_CARDS];
static uint port[MAX_PORTS];
static uint debug;
static uint poll;
+static int clock;
static uint timer;
static uint clockdelay_te = CLKDEL_TE;
static uint clockdelay_nt = CLKDEL_NT;
@@ -209,14 +211,16 @@ static int HFC_cnt, Port_cnt, PCM_cnt = 99;
MODULE_AUTHOR("Andreas Eversberg");
MODULE_LICENSE("GPL");
+MODULE_VERSION(HFC_MULTI_VERSION);
module_param(debug, uint, S_IRUGO | S_IWUSR);
module_param(poll, uint, S_IRUGO | S_IWUSR);
+module_param(clock, int, S_IRUGO | S_IWUSR);
module_param(timer, uint, S_IRUGO | S_IWUSR);
module_param(clockdelay_te, uint, S_IRUGO | S_IWUSR);
module_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR);
module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(pcm, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(dslot, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(dslot, int, NULL, S_IRUGO | S_IWUSR);
module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR);
module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR);
@@ -1419,19 +1423,6 @@ controller_fail:
HFC_outb(hc, R_TI_WD, poll_timer);
hc->hw.r_irqmsk_misc |= V_TI_IRQMSK;
- /*
- * set up 125us interrupt, only if function pointer is available
- * and module parameter timer is set
- */
- if (timer && hfc_interrupt && register_interrupt) {
- /* only one chip should use this interrupt */
- timer = 0;
- interrupt_registered = 1;
- hc->hw.r_irqmsk_misc |= V_PROC_IRQMSK;
- /* deactivate other interrupts in ztdummy */
- register_interrupt();
- }
-
/* set E1 state machine IRQ */
if (hc->type == 1)
hc->hw.r_irqmsk_misc |= V_STA_IRQMSK;
@@ -1991,6 +1982,17 @@ next_frame:
return; /* no data */
}
+ /* "fill fifo if empty" feature */
+ if (bch && test_bit(FLG_FILLEMPTY, &bch->Flags)
+ && !test_bit(FLG_HDLC, &bch->Flags) && z2 == z1) {
+ if (debug & DEBUG_HFCMULTI_FILL)
+ printk(KERN_DEBUG "%s: buffer empty, so we have "
+ "underrun\n", __func__);
+ /* fill buffer, to prevent future underrun */
+ hc->write_fifo(hc, hc->silence_data, poll >> 1);
+ Zspace -= (poll >> 1);
+ }
+
/* if audio data and connected slot */
if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && (!*txpending)
&& slot_tx >= 0) {
@@ -2027,7 +2029,6 @@ next_frame:
__func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i,
temp ? "HDLC":"TRANS");
-
/* Have to prep the audio data */
hc->write_fifo(hc, d, ii - i);
*idxp = ii;
@@ -2066,7 +2067,7 @@ next_frame:
* no more data at all. this prevents sending an undefined value.
*/
if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags))
- HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence);
+ HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
}
@@ -2583,7 +2584,6 @@ hfcmulti_interrupt(int intno, void *dev_id)
static int iq1 = 0, iq2 = 0, iq3 = 0, iq4 = 0,
iq5 = 0, iq6 = 0, iqcnt = 0;
#endif
- static int count;
struct hfc_multi *hc = dev_id;
struct dchannel *dch;
u_char r_irq_statech, status, r_irq_misc, r_irq_oview;
@@ -2637,6 +2637,7 @@ hfcmulti_interrupt(int intno, void *dev_id)
iqcnt = 0;
}
#endif
+
if (!r_irq_statech &&
!(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA |
V_MISC_IRQSTA | V_FR_IRQSTA))) {
@@ -2657,6 +2658,7 @@ hfcmulti_interrupt(int intno, void *dev_id)
if (status & V_MISC_IRQSTA) {
/* misc IRQ */
r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC);
+ r_irq_misc &= hc->hw.r_irqmsk_misc; /* ignore disabled irqs */
if (r_irq_misc & V_STA_IRQ) {
if (hc->type == 1) {
/* state machine */
@@ -2691,23 +2693,20 @@ hfcmulti_interrupt(int intno, void *dev_id)
plxsd_checksync(hc, 0);
}
}
- if (r_irq_misc & V_TI_IRQ)
+ if (r_irq_misc & V_TI_IRQ) {
+ if (hc->iclock_on)
+ mISDN_clock_update(hc->iclock, poll, NULL);
handle_timer_irq(hc);
+ }
if (r_irq_misc & V_DTMF_IRQ) {
- /* -> DTMF IRQ */
hfcmulti_dtmf(hc);
}
- /* TODO: REPLACE !!!! 125 us Interrupts are not acceptable */
if (r_irq_misc & V_IRQ_PROC) {
- /* IRQ every 125us */
- count++;
- /* generate 1kHz signal */
- if (count == 8) {
- if (hfc_interrupt)
- hfc_interrupt();
- count = 0;
- }
+ static int irq_proc_cnt;
+ if (!irq_proc_cnt++)
+ printk(KERN_WARNING "%s: got V_IRQ_PROC -"
+ " this should not happen\n", __func__);
}
}
@@ -2954,7 +2953,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx,
HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
HFC_wait(hc);
/* tx silence */
- HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence);
+ HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
HFC_outb(hc, R_SLOT, (((ch / 4) * 8) +
((ch % 4) * 4)) << 1);
HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1));
@@ -2969,7 +2968,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx,
HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
HFC_wait(hc);
/* tx silence */
- HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence);
+ HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
/* enable RX fifo */
HFC_outb(hc, R_FIFO, (ch<<1)|1);
HFC_wait(hc);
@@ -3461,7 +3460,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
switch (cq->op) {
case MISDN_CTRL_GETOP:
cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP
- | MISDN_CTRL_RX_OFF;
+ | MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY;
break;
case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
hc->chan[bch->slot].rx_off = !!cq->p1;
@@ -3476,6 +3475,12 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n",
__func__, bch->nr, hc->chan[bch->slot].rx_off);
break;
+ case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */
+ test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
+ if (debug & DEBUG_HFCMULTI_MSG)
+ printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d "
+ "off=%d)\n", __func__, bch->nr, !!cq->p1);
+ break;
case MISDN_CTRL_HW_FEATURES: /* fill features structure */
if (debug & DEBUG_HFCMULTI_MSG)
printk(KERN_DEBUG "%s: HW_FEATURE request\n",
@@ -3610,7 +3615,7 @@ hfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
static void
ph_state_change(struct dchannel *dch)
{
- struct hfc_multi *hc = dch->hw;
+ struct hfc_multi *hc;
int ch, i;
if (!dch) {
@@ -3618,6 +3623,7 @@ ph_state_change(struct dchannel *dch)
__func__);
return;
}
+ hc = dch->hw;
ch = dch->slot;
if (hc->type == 1) {
@@ -3992,6 +3998,7 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch,
}
if (test_and_set_bit(FLG_OPEN, &bch->Flags))
return -EBUSY; /* b-channel can be only open once */
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
bch->ch.protocol = rq->protocol;
hc->chan[ch].rx_off = 0;
rq->ch = &bch->ch;
@@ -4081,6 +4088,15 @@ hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
return err;
}
+static int
+clockctl(void *priv, int enable)
+{
+ struct hfc_multi *hc = priv;
+
+ hc->iclock_on = enable;
+ return 0;
+}
+
/*
* initialize the card
*/
@@ -4495,10 +4511,14 @@ release_card(struct hfc_multi *hc)
printk(KERN_WARNING "%s: release card (%d) entered\n",
__func__, hc->id);
+ /* unregister clock source */
+ if (hc->iclock)
+ mISDN_unregister_clock(hc->iclock);
+
+ /* disable irq */
spin_lock_irqsave(&hc->lock, flags);
disable_hwirq(hc);
spin_unlock_irqrestore(&hc->lock, flags);
-
udelay(1000);
/* dimm leds */
@@ -4699,7 +4719,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m)
} else
hc->chan[hc->dslot].jitter = 2; /* default */
snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1);
- ret = mISDN_register_device(&dch->dev, name);
+ ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name);
if (ret)
goto free_chan;
hc->created[0] = 1;
@@ -4807,9 +4827,9 @@ init_multi_port(struct hfc_multi *hc, int pt)
test_and_set_bit(HFC_CFG_DIS_ECHANNEL,
&hc->chan[i + 2].cfg);
}
- snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d/%d",
+ snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d",
hc->type, HFC_cnt + 1, pt + 1);
- ret = mISDN_register_device(&dch->dev, name);
+ ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name);
if (ret)
goto free_chan;
hc->created[pt] = 1;
@@ -4828,6 +4848,7 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent)
struct hfc_multi *hc;
u_long flags;
u_char dips = 0, pmj = 0; /* dip settings, port mode Jumpers */
+ int i;
if (HFC_cnt >= MAX_CARDS) {
printk(KERN_ERR "too many cards (max=%d).\n",
@@ -4861,11 +4882,11 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent)
hc->id = HFC_cnt;
hc->pcm = pcm[HFC_cnt];
hc->io_mode = iomode[HFC_cnt];
- if (dslot[HFC_cnt] < 0) {
+ if (dslot[HFC_cnt] < 0 && hc->type == 1) {
hc->dslot = 0;
printk(KERN_INFO "HFC-E1 card has disabled D-channel, but "
"31 B-channels\n");
- } if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32) {
+ } if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32 && hc->type == 1) {
hc->dslot = dslot[HFC_cnt];
printk(KERN_INFO "HFC-E1 card has alternating D-channel on "
"time slot %d\n", dslot[HFC_cnt]);
@@ -4876,9 +4897,17 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent)
hc->masterclk = -1;
if (type[HFC_cnt] & 0x100) {
test_and_set_bit(HFC_CHIP_ULAW, &hc->chip);
- silence = 0xff; /* ulaw silence */
+ hc->silence = 0xff; /* ulaw silence */
} else
- silence = 0x2a; /* alaw silence */
+ hc->silence = 0x2a; /* alaw silence */
+ if ((poll >> 1) > sizeof(hc->silence_data)) {
+ printk(KERN_ERR "HFCMULTI error: silence_data too small, "
+ "please fix\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < (poll >> 1); i++)
+ hc->silence_data[i] = hc->silence;
+
if (!(type[HFC_cnt] & 0x200))
test_and_set_bit(HFC_CHIP_DTMF, &hc->chip);
@@ -4945,9 +4974,7 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent)
switch (m->dip_type) {
case DIP_4S:
/*
- * get DIP Setting for beroNet 1S/2S/4S cards
- * check if Port Jumper config matches
- * module param 'protocol'
+ * Get DIP setting for beroNet 1S/2S/4S cards
* DIP Setting: (collect GPIO 13/14/15 (R_GPIO_IN1) +
* GPI 19/23 (R_GPI_IN2))
*/
@@ -4966,9 +4993,8 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent)
break;
case DIP_8S:
/*
- * get DIP Setting for beroNet 8S0+ cards
- *
- * enable PCI auxbridge function
+ * Get DIP Setting for beroNet 8S0+ cards
+ * Enable PCI auxbridge function
*/
HFC_outb(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK);
/* prepare access to auxport */
@@ -5003,6 +5029,10 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent)
list_add_tail(&hc->list, &HFClist);
spin_unlock_irqrestore(&HFClock, flags);
+ /* use as clock source */
+ if (clock == HFC_cnt + 1)
+ hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc);
+
/* initialize hardware */
ret_err = init_card(hc);
if (ret_err) {
@@ -5137,8 +5167,7 @@ static struct pci_device_id hfmultipci_ids[] __devinitdata = {
{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
PCI_DEVICE_ID_CCD_HFC8S, 0, 0, H(14)}, /* old Eval */
{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
- PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)},
- /* IOB8ST Recording */
+ PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, /* IOB8ST Recording */
{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
PCI_SUBDEVICE_ID_CCD_IOB8ST, 0, 0, H(16)}, /* IOB8ST */
{ PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
@@ -5188,18 +5217,16 @@ hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct hm_map *m = (struct hm_map *)ent->driver_data;
int ret;
- if (m == NULL) {
- if (ent->vendor == PCI_VENDOR_ID_CCD)
- if (ent->device == PCI_DEVICE_ID_CCD_HFC4S ||
- ent->device == PCI_DEVICE_ID_CCD_HFC8S ||
- ent->device == PCI_DEVICE_ID_CCD_HFCE1)
- printk(KERN_ERR
- "unknown HFC multiport controller "
- "(vendor:%x device:%x subvendor:%x "
- "subdevice:%x) Please contact the "
- "driver maintainer for support.\n",
- ent->vendor, ent->device,
- ent->subvendor, ent->subdevice);
+ if (m == NULL && ent->vendor == PCI_VENDOR_ID_CCD && (
+ ent->device == PCI_DEVICE_ID_CCD_HFC4S ||
+ ent->device == PCI_DEVICE_ID_CCD_HFC8S ||
+ ent->device == PCI_DEVICE_ID_CCD_HFCE1)) {
+ printk(KERN_ERR
+ "Unknown HFC multiport controller (vendor:%x device:%x "
+ "subvendor:%x subdevice:%x)\n", ent->vendor, ent->device,
+ ent->subvendor, ent->subdevice);
+ printk(KERN_ERR
+ "Please contact the driver maintainer for support.\n");
return -ENODEV;
}
ret = hfcmulti_init(pdev, ent);
@@ -5222,22 +5249,9 @@ HFCmulti_cleanup(void)
{
struct hfc_multi *card, *next;
- /* unload interrupt function symbol */
- if (hfc_interrupt)
- symbol_put(ztdummy_extern_interrupt);
- if (register_interrupt)
- symbol_put(ztdummy_register_interrupt);
- if (unregister_interrupt) {
- if (interrupt_registered) {
- interrupt_registered = 0;
- unregister_interrupt();
- }
- symbol_put(ztdummy_unregister_interrupt);
- }
-
+ /* get rid of all devices of this driver */
list_for_each_entry_safe(card, next, &HFClist, list)
release_card(card);
- /* get rid of all devices of this driver */
pci_unregister_driver(&hfcmultipci_driver);
}
@@ -5246,8 +5260,10 @@ HFCmulti_init(void)
{
int err;
+ printk(KERN_INFO "mISDN: HFC-multi driver %s\n", HFC_MULTI_VERSION);
+
#ifdef IRQ_DEBUG
- printk(KERN_ERR "%s: IRQ_DEBUG IS ENABLED!\n", __func__);
+ printk(KERN_DEBUG "%s: IRQ_DEBUG IS ENABLED!\n", __func__);
#endif
spin_lock_init(&HFClock);
@@ -5256,22 +5272,11 @@ HFCmulti_init(void)
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_DEBUG "%s: init entered\n", __func__);
- hfc_interrupt = symbol_get(ztdummy_extern_interrupt);
- register_interrupt = symbol_get(ztdummy_register_interrupt);
- unregister_interrupt = symbol_get(ztdummy_unregister_interrupt);
- printk(KERN_INFO "mISDN: HFC-multi driver %s\n",
- hfcmulti_revision);
-
switch (poll) {
case 0:
poll_timer = 6;
poll = 128;
break;
- /*
- * wenn dieses break nochmal verschwindet,
- * gibt es heisse ohren :-)
- * "without the break you will get hot ears ???"
- */
case 8:
poll_timer = 2;
break;
@@ -5298,20 +5303,12 @@ HFCmulti_init(void)
}
+ if (!clock)
+ clock = 1;
+
err = pci_register_driver(&hfcmultipci_driver);
if (err < 0) {
printk(KERN_ERR "error registering pci driver: %x\n", err);
- if (hfc_interrupt)
- symbol_put(ztdummy_extern_interrupt);
- if (register_interrupt)
- symbol_put(ztdummy_register_interrupt);
- if (unregister_interrupt) {
- if (interrupt_registered) {
- interrupt_registered = 0;
- unregister_interrupt();
- }
- symbol_put(ztdummy_unregister_interrupt);
- }
return err;
}
return 0;
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index cd8302af40eb..f0e14dfcf71d 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -23,6 +23,25 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
+ * Module options:
+ *
+ * debug:
+ * NOTE: only one poll value must be given for all cards
+ * See hfc_pci.h for debug flags.
+ *
+ * poll:
+ * NOTE: only one poll value must be given for all cards
+ * Give the number of samples for each fifo process.
+ * By default 128 is used. Decrease to reduce delay, increase to
+ * reduce cpu load. If unsure, don't mess with it!
+ * A value of 128 will use controller's interrupt. Other values will
+ * use kernel timer, because the controller will not allow lower values
+ * than 128.
+ * Also note that the value depends on the kernel timer frequency.
+ * If kernel uses a frequency of 1000 Hz, steps of 8 samples are possible.
+ * If the kernel uses 100 Hz, steps of 80 samples are possible.
+ * If the kernel uses 300 Hz, steps of about 26 samples are possible.
+ *
*/
#include <linux/module.h>
@@ -34,16 +53,16 @@
static const char *hfcpci_revision = "2.0";
-#define MAX_CARDS 8
static int HFC_cnt;
static uint debug;
+static uint poll, tics;
+struct timer_list hfc_tl;
+u32 hfc_jiffies;
MODULE_AUTHOR("Karsten Keil");
MODULE_LICENSE("GPL");
-module_param(debug, uint, 0);
-
-static LIST_HEAD(HFClist);
-static DEFINE_RWLOCK(HFClock);
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+module_param(poll, uint, S_IRUGO | S_IWUSR);
enum {
HFC_CCD_2BD0,
@@ -114,7 +133,6 @@ struct hfcPCI_hw {
struct hfc_pci {
- struct list_head list;
u_char subtype;
u_char chanlimit;
u_char initdone;
@@ -520,9 +538,9 @@ receive_dmsg(struct hfc_pci *hc)
}
/*
- * check for transparent receive data and read max one threshold size if avail
+ * check for transparent receive data and read max one 'poll' size if avail
*/
-static int
+static void
hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata)
{
__le16 *z1r, *z2r;
@@ -534,17 +552,19 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata)
fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r);
if (!fcnt)
- return 0; /* no data avail */
+ return; /* no data avail */
if (fcnt <= 0)
fcnt += B_FIFO_SIZE; /* bytes actually buffered */
- if (fcnt > HFCPCI_BTRANS_THRESHOLD)
- fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */
-
new_z2 = le16_to_cpu(*z2r) + fcnt; /* new position in fifo */
if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL))
new_z2 -= B_FIFO_SIZE; /* buffer wrap */
+ if (fcnt > MAX_DATA_SIZE) { /* flush, if oversized */
+ *z2r = cpu_to_le16(new_z2); /* new position */
+ return;
+ }
+
bch->rx_skb = mI_alloc_skb(fcnt, GFP_ATOMIC);
if (bch->rx_skb) {
ptr = skb_put(bch->rx_skb, fcnt);
@@ -569,7 +589,6 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata)
printk(KERN_WARNING "HFCPCI: receive out of memory\n");
*z2r = cpu_to_le16(new_z2); /* new position */
- return 1;
}
/*
@@ -580,12 +599,11 @@ main_rec_hfcpci(struct bchannel *bch)
{
struct hfc_pci *hc = bch->hw;
int rcnt, real_fifo;
- int receive, count = 5;
+ int receive = 0, count = 5;
struct bzfifo *bz;
u_char *bdata;
struct zt *zp;
-
if ((bch->nr & 2) && (!hc->hw.bswapped)) {
bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2;
bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2;
@@ -625,9 +643,10 @@ Begin:
receive = 1;
else
receive = 0;
- } else if (test_bit(FLG_TRANSPARENT, &bch->Flags))
- receive = hfcpci_empty_fifo_trans(bch, bz, bdata);
- else
+ } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+ hfcpci_empty_fifo_trans(bch, bz, bdata);
+ return;
+ } else
receive = 0;
if (count && receive)
goto Begin;
@@ -751,11 +770,41 @@ hfcpci_fill_fifo(struct bchannel *bch)
/* fcnt contains available bytes in fifo */
fcnt = B_FIFO_SIZE - fcnt;
/* remaining bytes to send (bytes in fifo) */
+
+ /* "fill fifo if empty" feature */
+ if (test_bit(FLG_FILLEMPTY, &bch->Flags) && !fcnt) {
+ /* printk(KERN_DEBUG "%s: buffer empty, so we have "
+ "underrun\n", __func__); */
+ /* fill buffer, to prevent future underrun */
+ count = HFCPCI_FILLEMPTY;
+ new_z1 = le16_to_cpu(*z1t) + count;
+ /* new buffer Position */
+ if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL))
+ new_z1 -= B_FIFO_SIZE; /* buffer wrap */
+ dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL);
+ maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t);
+ /* end of fifo */
+ if (bch->debug & DEBUG_HW_BFIFO)
+ printk(KERN_DEBUG "hfcpci_FFt fillempty "
+ "fcnt(%d) maxl(%d) nz1(%x) dst(%p)\n",
+ fcnt, maxlen, new_z1, dst);
+ fcnt += count;
+ if (maxlen > count)
+ maxlen = count; /* limit size */
+ memset(dst, 0x2a, maxlen); /* first copy */
+ count -= maxlen; /* remaining bytes */
+ if (count) {
+ dst = bdata; /* start of buffer */
+ memset(dst, 0x2a, count);
+ }
+ *z1t = cpu_to_le16(new_z1); /* now send data */
+ }
+
next_t_frame:
count = bch->tx_skb->len - bch->tx_idx;
- /* maximum fill shall be HFCPCI_BTRANS_MAX */
- if (count > HFCPCI_BTRANS_MAX - fcnt)
- count = HFCPCI_BTRANS_MAX - fcnt;
+ /* maximum fill shall be poll*2 */
+ if (count > (poll << 1) - fcnt)
+ count = (poll << 1) - fcnt;
if (count <= 0)
return;
/* data is suitable for fifo */
@@ -1135,37 +1184,37 @@ hfcpci_int(int intno, void *dev_id)
val &= ~0x80;
Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER);
}
- if (val & 0x08) {
+ if (val & 0x08) { /* B1 rx */
bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
if (bch)
main_rec_hfcpci(bch);
else if (hc->dch.debug)
printk(KERN_DEBUG "hfcpci spurious 0x08 IRQ\n");
}
- if (val & 0x10) {
+ if (val & 0x10) { /* B2 rx */
bch = Sel_BCS(hc, 2);
if (bch)
main_rec_hfcpci(bch);
else if (hc->dch.debug)
printk(KERN_DEBUG "hfcpci spurious 0x10 IRQ\n");
}
- if (val & 0x01) {
+ if (val & 0x01) { /* B1 tx */
bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
if (bch)
tx_birq(bch);
else if (hc->dch.debug)
printk(KERN_DEBUG "hfcpci spurious 0x01 IRQ\n");
}
- if (val & 0x02) {
+ if (val & 0x02) { /* B2 tx */
bch = Sel_BCS(hc, 2);
if (bch)
tx_birq(bch);
else if (hc->dch.debug)
printk(KERN_DEBUG "hfcpci spurious 0x02 IRQ\n");
}
- if (val & 0x20)
+ if (val & 0x20) /* D rx */
receive_dmsg(hc);
- if (val & 0x04) { /* dframe transmitted */
+ if (val & 0x04) { /* D tx */
if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags))
del_timer(&hc->dch.timer);
tx_dirq(&hc->dch);
@@ -1283,14 +1332,16 @@ mode_hfcpci(struct bchannel *bch, int bc, int protocol)
}
if (fifo2 & 2) {
hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
- hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS +
- HFCPCI_INTS_B2REC);
+ if (!tics)
+ hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS +
+ HFCPCI_INTS_B2REC);
hc->hw.ctmt |= 2;
hc->hw.conn &= ~0x18;
} else {
hc->hw.fifo_en |= HFCPCI_FIFOEN_B1;
- hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS +
- HFCPCI_INTS_B1REC);
+ if (!tics)
+ hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS +
+ HFCPCI_INTS_B1REC);
hc->hw.ctmt |= 1;
hc->hw.conn &= ~0x03;
}
@@ -1398,7 +1449,8 @@ set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan)
if (chan & 2) {
hc->hw.sctrl_r |= SCTRL_B2_ENA;
hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX;
- hc->hw.int_m1 |= HFCPCI_INTS_B2REC;
+ if (!tics)
+ hc->hw.int_m1 |= HFCPCI_INTS_B2REC;
hc->hw.ctmt |= 2;
hc->hw.conn &= ~0x18;
#ifdef REVERSE_BITORDER
@@ -1407,7 +1459,8 @@ set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan)
} else {
hc->hw.sctrl_r |= SCTRL_B1_ENA;
hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX;
- hc->hw.int_m1 |= HFCPCI_INTS_B1REC;
+ if (!tics)
+ hc->hw.int_m1 |= HFCPCI_INTS_B1REC;
hc->hw.ctmt |= 1;
hc->hw.conn &= ~0x03;
#ifdef REVERSE_BITORDER
@@ -1481,11 +1534,17 @@ deactivate_bchannel(struct bchannel *bch)
static int
channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
{
- int ret = 0;
+ int ret = 0;
switch (cq->op) {
case MISDN_CTRL_GETOP:
- cq->op = 0;
+ cq->op = MISDN_CTRL_FILL_EMPTY;
+ break;
+ case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */
+ test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
+ if (debug & DEBUG_HW_OPEN)
+ printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d "
+ "off=%d)\n", __func__, bch->nr, !!cq->p1);
break;
default:
printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op);
@@ -1859,6 +1918,10 @@ open_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch,
hc->dch.dev.id, __builtin_return_address(0));
if (rq->protocol == ISDN_P_NONE)
return -EINVAL;
+ if (rq->adr.channel == 1) {
+ /* TODO: E-Channel */
+ return -EINVAL;
+ }
if (!hc->initdone) {
if (rq->protocol == ISDN_P_TE_S0) {
err = create_l1(&hc->dch, hfc_l1callback);
@@ -1874,6 +1937,11 @@ open_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch,
if (rq->protocol != ch->protocol) {
if (hc->hw.protocol == ISDN_P_TE_S0)
l1_event(hc->dch.l1, CLOSE_CHANNEL);
+ if (rq->protocol == ISDN_P_TE_S0) {
+ err = create_l1(&hc->dch, hfc_l1callback);
+ if (err)
+ return err;
+ }
hc->hw.protocol = rq->protocol;
ch->protocol = rq->protocol;
hfcpci_setmode(hc);
@@ -1903,6 +1971,7 @@ open_bchannel(struct hfc_pci *hc, struct channel_req *rq)
bch = &hc->bch[rq->adr.channel - 1];
if (test_and_set_bit(FLG_OPEN, &bch->Flags))
return -EBUSY; /* b-channel can be only open once */
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
bch->ch.protocol = rq->protocol;
rq->ch = &bch->ch; /* TODO: E-channel */
if (!try_module_get(THIS_MODULE))
@@ -1928,7 +1997,8 @@ hfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
switch (cmd) {
case OPEN_CHANNEL:
rq = arg;
- if (rq->adr.channel == 0)
+ if ((rq->protocol == ISDN_P_TE_S0) ||
+ (rq->protocol == ISDN_P_NT_S0))
err = open_dchannel(hc, ch, rq);
else
err = open_bchannel(hc, rq);
@@ -2027,7 +2097,6 @@ release_card(struct hfc_pci *hc) {
mISDN_freebchannel(&hc->bch[1]);
mISDN_freebchannel(&hc->bch[0]);
mISDN_freedchannel(&hc->dch);
- list_del(&hc->list);
pci_set_drvdata(hc->pdev, NULL);
kfree(hc);
}
@@ -2037,12 +2106,8 @@ setup_card(struct hfc_pci *card)
{
int err = -EINVAL;
u_int i;
- u_long flags;
char name[MISDN_MAX_IDLEN];
- if (HFC_cnt >= MAX_CARDS)
- return -EINVAL; /* maybe better value */
-
card->dch.debug = debug;
spin_lock_init(&card->lock);
mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, ph_state);
@@ -2068,13 +2133,10 @@ setup_card(struct hfc_pci *card)
if (err)
goto error;
snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1);
- err = mISDN_register_device(&card->dch.dev, name);
+ err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, name);
if (err)
goto error;
HFC_cnt++;
- write_lock_irqsave(&HFClock, flags);
- list_add_tail(&card->list, &HFClist);
- write_unlock_irqrestore(&HFClock, flags);
printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt);
return 0;
error:
@@ -2210,15 +2272,12 @@ static void __devexit
hfc_remove_pci(struct pci_dev *pdev)
{
struct hfc_pci *card = pci_get_drvdata(pdev);
- u_long flags;
- if (card) {
- write_lock_irqsave(&HFClock, flags);
+ if (card)
release_card(card);
- write_unlock_irqrestore(&HFClock, flags);
- } else
+ else
if (debug)
- printk(KERN_WARNING "%s: drvdata allready removed\n",
+ printk(KERN_WARNING "%s: drvdata already removed\n",
__func__);
}
@@ -2230,25 +2289,97 @@ static struct pci_driver hfc_driver = {
.id_table = hfc_ids,
};
+static int
+_hfcpci_softirq(struct device *dev, void *arg)
+{
+ struct hfc_pci *hc = dev_get_drvdata(dev);
+ struct bchannel *bch;
+ if (hc == NULL)
+ return 0;
+
+ if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) {
+ spin_lock(&hc->lock);
+ bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1);
+ if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */
+ main_rec_hfcpci(bch);
+ tx_birq(bch);
+ }
+ bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2);
+ if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */
+ main_rec_hfcpci(bch);
+ tx_birq(bch);
+ }
+ spin_unlock(&hc->lock);
+ }
+ return 0;
+}
+
+static void
+hfcpci_softirq(void *arg)
+{
+ (void) driver_for_each_device(&hfc_driver.driver, NULL, arg,
+ _hfcpci_softirq);
+
+ /* if next event would be in the past ... */
+ if ((s32)(hfc_jiffies + tics - jiffies) <= 0)
+ hfc_jiffies = jiffies + 1;
+ else
+ hfc_jiffies += tics;
+ hfc_tl.expires = hfc_jiffies;
+ add_timer(&hfc_tl);
+}
+
static int __init
HFC_init(void)
{
int err;
+ if (!poll)
+ poll = HFCPCI_BTRANS_THRESHOLD;
+
+ if (poll != HFCPCI_BTRANS_THRESHOLD) {
+ tics = (poll * HZ) / 8000;
+ if (tics < 1)
+ tics = 1;
+ poll = (tics * 8000) / HZ;
+ if (poll > 256 || poll < 8) {
+ printk(KERN_ERR "%s: Wrong poll value %d not in range "
+ "of 8..256.\n", __func__, poll);
+ err = -EINVAL;
+ return err;
+ }
+ }
+ if (poll != HFCPCI_BTRANS_THRESHOLD) {
+ printk(KERN_INFO "%s: Using alternative poll value of %d\n",
+ __func__, poll);
+ hfc_tl.function = (void *)hfcpci_softirq;
+ hfc_tl.data = 0;
+ init_timer(&hfc_tl);
+ hfc_tl.expires = jiffies + tics;
+ hfc_jiffies = hfc_tl.expires;
+ add_timer(&hfc_tl);
+ } else
+ tics = 0; /* indicate the use of controller's timer */
+
err = pci_register_driver(&hfc_driver);
+ if (err) {
+ if (timer_pending(&hfc_tl))
+ del_timer(&hfc_tl);
+ }
+
return err;
}
static void __exit
HFC_cleanup(void)
{
- struct hfc_pci *card, *next;
+ if (timer_pending(&hfc_tl))
+ del_timer(&hfc_tl);
- list_for_each_entry_safe(card, next, &HFClist, list) {
- release_card(card);
- }
pci_unregister_driver(&hfc_driver);
}
module_init(HFC_init);
module_exit(HFC_cleanup);
+
+MODULE_DEVICE_TABLE(pci, hfc_ids);
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
new file mode 100644
index 000000000000..ba6925fbf38a
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -0,0 +1,2196 @@
+/* hfcsusb.c
+ * mISDN driver for Colognechip HFC-S USB chip
+ *
+ * Copyright 2001 by Peter Sprenger (sprenger@moving-bytes.de)
+ * Copyright 2008 by Martin Bachem (info@bachem-it.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, 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.
+ *
+ *
+ * module params
+ * debug=<n>, default=0, with n=0xHHHHGGGG
+ * H - l1 driver flags described in hfcsusb.h
+ * G - common mISDN debug flags described at mISDNhw.h
+ *
+ * poll=<n>, default 128
+ * n : burst size of PH_DATA_IND at transparent rx data
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/usb.h>
+#include <linux/mISDNhw.h>
+#include "hfcsusb.h"
+
+const char *hfcsusb_rev = "Revision: 0.3.3 (socket), 2008-11-05";
+
+static unsigned int debug;
+static int poll = DEFAULT_TRANSP_BURST_SZ;
+
+static LIST_HEAD(HFClist);
+static DEFINE_RWLOCK(HFClock);
+
+
+MODULE_AUTHOR("Martin Bachem");
+MODULE_LICENSE("GPL");
+module_param(debug, uint, S_IRUGO | S_IWUSR);
+module_param(poll, int, 0);
+
+static int hfcsusb_cnt;
+
+/* some function prototypes */
+static void hfcsusb_ph_command(struct hfcsusb *hw, u_char command);
+static void release_hw(struct hfcsusb *hw);
+static void reset_hfcsusb(struct hfcsusb *hw);
+static void setPortMode(struct hfcsusb *hw);
+static void hfcsusb_start_endpoint(struct hfcsusb *hw, int channel);
+static void hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel);
+static int hfcsusb_setup_bch(struct bchannel *bch, int protocol);
+static void deactivate_bchannel(struct bchannel *bch);
+static void hfcsusb_ph_info(struct hfcsusb *hw);
+
+/* start next background transfer for control channel */
+static void
+ctrl_start_transfer(struct hfcsusb *hw)
+{
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
+
+ if (hw->ctrl_cnt) {
+ hw->ctrl_urb->pipe = hw->ctrl_out_pipe;
+ hw->ctrl_urb->setup_packet = (u_char *)&hw->ctrl_write;
+ hw->ctrl_urb->transfer_buffer = NULL;
+ hw->ctrl_urb->transfer_buffer_length = 0;
+ hw->ctrl_write.wIndex =
+ cpu_to_le16(hw->ctrl_buff[hw->ctrl_out_idx].hfcs_reg);
+ hw->ctrl_write.wValue =
+ cpu_to_le16(hw->ctrl_buff[hw->ctrl_out_idx].reg_val);
+
+ usb_submit_urb(hw->ctrl_urb, GFP_ATOMIC);
+ }
+}
+
+/*
+ * queue a control transfer request to write HFC-S USB
+ * chip register using CTRL resuest queue
+ */
+static int write_reg(struct hfcsusb *hw, __u8 reg, __u8 val)
+{
+ struct ctrl_buf *buf;
+
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s reg(0x%02x) val(0x%02x)\n",
+ hw->name, __func__, reg, val);
+
+ spin_lock(&hw->ctrl_lock);
+ if (hw->ctrl_cnt >= HFC_CTRL_BUFSIZE)
+ return 1;
+ buf = &hw->ctrl_buff[hw->ctrl_in_idx];
+ buf->hfcs_reg = reg;
+ buf->reg_val = val;
+ if (++hw->ctrl_in_idx >= HFC_CTRL_BUFSIZE)
+ hw->ctrl_in_idx = 0;
+ if (++hw->ctrl_cnt == 1)
+ ctrl_start_transfer(hw);
+ spin_unlock(&hw->ctrl_lock);
+
+ return 0;
+}
+
+/* control completion routine handling background control cmds */
+static void
+ctrl_complete(struct urb *urb)
+{
+ struct hfcsusb *hw = (struct hfcsusb *) urb->context;
+ struct ctrl_buf *buf;
+
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
+
+ urb->dev = hw->dev;
+ if (hw->ctrl_cnt) {
+ buf = &hw->ctrl_buff[hw->ctrl_out_idx];
+ hw->ctrl_cnt--; /* decrement actual count */
+ if (++hw->ctrl_out_idx >= HFC_CTRL_BUFSIZE)
+ hw->ctrl_out_idx = 0; /* pointer wrap */
+
+ ctrl_start_transfer(hw); /* start next transfer */
+ }
+}
+
+/* handle LED bits */
+static void
+set_led_bit(struct hfcsusb *hw, signed short led_bits, int set_on)
+{
+ if (set_on) {
+ if (led_bits < 0)
+ hw->led_state &= ~abs(led_bits);
+ else
+ hw->led_state |= led_bits;
+ } else {
+ if (led_bits < 0)
+ hw->led_state |= abs(led_bits);
+ else
+ hw->led_state &= ~led_bits;
+ }
+}
+
+/* handle LED requests */
+static void
+handle_led(struct hfcsusb *hw, int event)
+{
+ struct hfcsusb_vdata *driver_info = (struct hfcsusb_vdata *)
+ hfcsusb_idtab[hw->vend_idx].driver_info;
+ __u8 tmpled;
+
+ if (driver_info->led_scheme == LED_OFF)
+ return;
+ tmpled = hw->led_state;
+
+ switch (event) {
+ case LED_POWER_ON:
+ set_led_bit(hw, driver_info->led_bits[0], 1);
+ set_led_bit(hw, driver_info->led_bits[1], 0);
+ set_led_bit(hw, driver_info->led_bits[2], 0);
+ set_led_bit(hw, driver_info->led_bits[3], 0);
+ break;
+ case LED_POWER_OFF:
+ set_led_bit(hw, driver_info->led_bits[0], 0);
+ set_led_bit(hw, driver_info->led_bits[1], 0);
+ set_led_bit(hw, driver_info->led_bits[2], 0);
+ set_led_bit(hw, driver_info->led_bits[3], 0);
+ break;
+ case LED_S0_ON:
+ set_led_bit(hw, driver_info->led_bits[1], 1);
+ break;
+ case LED_S0_OFF:
+ set_led_bit(hw, driver_info->led_bits[1], 0);
+ break;
+ case LED_B1_ON:
+ set_led_bit(hw, driver_info->led_bits[2], 1);
+ break;
+ case LED_B1_OFF:
+ set_led_bit(hw, driver_info->led_bits[2], 0);
+ break;
+ case LED_B2_ON:
+ set_led_bit(hw, driver_info->led_bits[3], 1);
+ break;
+ case LED_B2_OFF:
+ set_led_bit(hw, driver_info->led_bits[3], 0);
+ break;
+ }
+
+ if (hw->led_state != tmpled) {
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s reg(0x%02x) val(x%02x)\n",
+ hw->name, __func__,
+ HFCUSB_P_DATA, hw->led_state);
+
+ write_reg(hw, HFCUSB_P_DATA, hw->led_state);
+ }
+}
+
+/*
+ * Layer2 -> Layer 1 Bchannel data
+ */
+static int
+hfcusb_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct hfcsusb *hw = bch->hw;
+ int ret = -EINVAL;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u_long flags;
+
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(&hw->lock, flags);
+ ret = bchannel_senddata(bch, skb);
+ spin_unlock_irqrestore(&hw->lock, flags);
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s PH_DATA_REQ ret(%i)\n",
+ hw->name, __func__, ret);
+ if (ret > 0) {
+ /*
+ * other l1 drivers don't send early confirms on
+ * transp data, but hfcsusb does because tx_next
+ * skb is needed in tx_iso_complete()
+ */
+ queue_ch_frame(ch, PH_DATA_CNF, hh->id, NULL);
+ ret = 0;
+ }
+ return ret;
+ case PH_ACTIVATE_REQ:
+ if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
+ hfcsusb_start_endpoint(hw, bch->nr);
+ ret = hfcsusb_setup_bch(bch, ch->protocol);
+ } else
+ ret = 0;
+ if (!ret)
+ _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
+ 0, NULL, GFP_KERNEL);
+ break;
+ case PH_DEACTIVATE_REQ:
+ deactivate_bchannel(bch);
+ _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY,
+ 0, NULL, GFP_KERNEL);
+ ret = 0;
+ break;
+ }
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+/*
+ * send full D/B channel status information
+ * as MPH_INFORMATION_IND
+ */
+static void
+hfcsusb_ph_info(struct hfcsusb *hw)
+{
+ struct ph_info *phi;
+ struct dchannel *dch = &hw->dch;
+ int i;
+
+ phi = kzalloc(sizeof(struct ph_info) +
+ dch->dev.nrbchan * sizeof(struct ph_info_ch), GFP_ATOMIC);
+ phi->dch.ch.protocol = hw->protocol;
+ phi->dch.ch.Flags = dch->Flags;
+ phi->dch.state = dch->state;
+ phi->dch.num_bch = dch->dev.nrbchan;
+ for (i = 0; i < dch->dev.nrbchan; i++) {
+ phi->bch[i].protocol = hw->bch[i].ch.protocol;
+ phi->bch[i].Flags = hw->bch[i].Flags;
+ }
+ _queue_data(&dch->dev.D, MPH_INFORMATION_IND, MISDN_ID_ANY,
+ sizeof(struct ph_info_dch) + dch->dev.nrbchan *
+ sizeof(struct ph_info_ch), phi, GFP_ATOMIC);
+}
+
+/*
+ * Layer2 -> Layer 1 Dchannel data
+ */
+static int
+hfcusb_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ struct hfcsusb *hw = dch->hw;
+ int ret = -EINVAL;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s: PH_DATA_REQ\n",
+ hw->name, __func__);
+
+ spin_lock_irqsave(&hw->lock, flags);
+ ret = dchannel_senddata(dch, skb);
+ spin_unlock_irqrestore(&hw->lock, flags);
+ if (ret > 0) {
+ ret = 0;
+ queue_ch_frame(ch, PH_DATA_CNF, hh->id, NULL);
+ }
+ break;
+
+ case PH_ACTIVATE_REQ:
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s: PH_ACTIVATE_REQ %s\n",
+ hw->name, __func__,
+ (hw->protocol == ISDN_P_NT_S0) ? "NT" : "TE");
+
+ if (hw->protocol == ISDN_P_NT_S0) {
+ ret = 0;
+ if (test_bit(FLG_ACTIVE, &dch->Flags)) {
+ _queue_data(&dch->dev.D,
+ PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_ATOMIC);
+ } else {
+ hfcsusb_ph_command(hw,
+ HFC_L1_ACTIVATE_NT);
+ test_and_set_bit(FLG_L2_ACTIVATED,
+ &dch->Flags);
+ }
+ } else {
+ hfcsusb_ph_command(hw, HFC_L1_ACTIVATE_TE);
+ ret = l1_event(dch->l1, hh->prim);
+ }
+ break;
+
+ case PH_DEACTIVATE_REQ:
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s: PH_DEACTIVATE_REQ\n",
+ hw->name, __func__);
+ test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
+
+ if (hw->protocol == ISDN_P_NT_S0) {
+ hfcsusb_ph_command(hw, HFC_L1_DEACTIVATE_NT);
+ spin_lock_irqsave(&hw->lock, flags);
+ skb_queue_purge(&dch->squeue);
+ if (dch->tx_skb) {
+ dev_kfree_skb(dch->tx_skb);
+ dch->tx_skb = NULL;
+ }
+ dch->tx_idx = 0;
+ if (dch->rx_skb) {
+ dev_kfree_skb(dch->rx_skb);
+ dch->rx_skb = NULL;
+ }
+ test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+ spin_unlock_irqrestore(&hw->lock, flags);
+#ifdef FIXME
+ if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
+ dchannel_sched_event(&hc->dch, D_CLEARBUSY);
+#endif
+ ret = 0;
+ } else
+ ret = l1_event(dch->l1, hh->prim);
+ break;
+ case MPH_INFORMATION_REQ:
+ hfcsusb_ph_info(hw);
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Layer 1 callback function
+ */
+static int
+hfc_l1callback(struct dchannel *dch, u_int cmd)
+{
+ struct hfcsusb *hw = dch->hw;
+
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s cmd 0x%x\n",
+ hw->name, __func__, cmd);
+
+ switch (cmd) {
+ case INFO3_P8:
+ case INFO3_P10:
+ case HW_RESET_REQ:
+ case HW_POWERUP_REQ:
+ break;
+
+ case HW_DEACT_REQ:
+ skb_queue_purge(&dch->squeue);
+ if (dch->tx_skb) {
+ dev_kfree_skb(dch->tx_skb);
+ dch->tx_skb = NULL;
+ }
+ dch->tx_idx = 0;
+ if (dch->rx_skb) {
+ dev_kfree_skb(dch->rx_skb);
+ dch->rx_skb = NULL;
+ }
+ test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+ break;
+ case PH_ACTIVATE_IND:
+ test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+ _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
+ GFP_ATOMIC);
+ break;
+ case PH_DEACTIVATE_IND:
+ test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+ _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
+ GFP_ATOMIC);
+ break;
+ default:
+ if (dch->debug & DEBUG_HW)
+ printk(KERN_DEBUG "%s: %s: unknown cmd %x\n",
+ hw->name, __func__, cmd);
+ return -1;
+ }
+ hfcsusb_ph_info(hw);
+ return 0;
+}
+
+static int
+open_dchannel(struct hfcsusb *hw, struct mISDNchannel *ch,
+ struct channel_req *rq)
+{
+ int err = 0;
+
+ if (debug & DEBUG_HW_OPEN)
+ printk(KERN_DEBUG "%s: %s: dev(%d) open addr(%i) from %p\n",
+ hw->name, __func__, hw->dch.dev.id, rq->adr.channel,
+ __builtin_return_address(0));
+ if (rq->protocol == ISDN_P_NONE)
+ return -EINVAL;
+
+ test_and_clear_bit(FLG_ACTIVE, &hw->dch.Flags);
+ test_and_clear_bit(FLG_ACTIVE, &hw->ech.Flags);
+ hfcsusb_start_endpoint(hw, HFC_CHAN_D);
+
+ /* E-Channel logging */
+ if (rq->adr.channel == 1) {
+ if (hw->fifos[HFCUSB_PCM_RX].pipe) {
+ hfcsusb_start_endpoint(hw, HFC_CHAN_E);
+ set_bit(FLG_ACTIVE, &hw->ech.Flags);
+ _queue_data(&hw->ech.dev.D, PH_ACTIVATE_IND,
+ MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
+ } else
+ return -EINVAL;
+ }
+
+ if (!hw->initdone) {
+ hw->protocol = rq->protocol;
+ if (rq->protocol == ISDN_P_TE_S0) {
+ err = create_l1(&hw->dch, hfc_l1callback);
+ if (err)
+ return err;
+ }
+ setPortMode(hw);
+ ch->protocol = rq->protocol;
+ hw->initdone = 1;
+ } else {
+ if (rq->protocol != ch->protocol)
+ return -EPROTONOSUPPORT;
+ }
+
+ if (((ch->protocol == ISDN_P_NT_S0) && (hw->dch.state == 3)) ||
+ ((ch->protocol == ISDN_P_TE_S0) && (hw->dch.state == 7)))
+ _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
+ 0, NULL, GFP_KERNEL);
+ rq->ch = ch;
+ if (!try_module_get(THIS_MODULE))
+ printk(KERN_WARNING "%s: %s: cannot get module\n",
+ hw->name, __func__);
+ return 0;
+}
+
+static int
+open_bchannel(struct hfcsusb *hw, struct channel_req *rq)
+{
+ struct bchannel *bch;
+
+ if (rq->adr.channel > 2)
+ return -EINVAL;
+ if (rq->protocol == ISDN_P_NONE)
+ return -EINVAL;
+
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s B%i\n",
+ hw->name, __func__, rq->adr.channel);
+
+ bch = &hw->bch[rq->adr.channel - 1];
+ if (test_and_set_bit(FLG_OPEN, &bch->Flags))
+ return -EBUSY; /* b-channel can be only open once */
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+ bch->ch.protocol = rq->protocol;
+ rq->ch = &bch->ch;
+
+ /* start USB endpoint for bchannel */
+ if (rq->adr.channel == 1)
+ hfcsusb_start_endpoint(hw, HFC_CHAN_B1);
+ else
+ hfcsusb_start_endpoint(hw, HFC_CHAN_B2);
+
+ if (!try_module_get(THIS_MODULE))
+ printk(KERN_WARNING "%s: %s:cannot get module\n",
+ hw->name, __func__);
+ return 0;
+}
+
+static int
+channel_ctrl(struct hfcsusb *hw, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s op(0x%x) channel(0x%x)\n",
+ hw->name, __func__, (cq->op), (cq->channel));
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT |
+ MISDN_CTRL_DISCONNECT;
+ break;
+ default:
+ printk(KERN_WARNING "%s: %s: unknown Op %x\n",
+ hw->name, __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+/*
+ * device control function
+ */
+static int
+hfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct hfcsusb *hw = dch->hw;
+ struct channel_req *rq;
+ int err = 0;
+
+ if (dch->debug & DEBUG_HW)
+ printk(KERN_DEBUG "%s: %s: cmd:%x %p\n",
+ hw->name, __func__, cmd, arg);
+ switch (cmd) {
+ case OPEN_CHANNEL:
+ rq = arg;
+ if ((rq->protocol == ISDN_P_TE_S0) ||
+ (rq->protocol == ISDN_P_NT_S0))
+ err = open_dchannel(hw, ch, rq);
+ else
+ err = open_bchannel(hw, rq);
+ if (!err)
+ hw->open++;
+ break;
+ case CLOSE_CHANNEL:
+ hw->open--;
+ if (debug & DEBUG_HW_OPEN)
+ printk(KERN_DEBUG
+ "%s: %s: dev(%d) close from %p (open %d)\n",
+ hw->name, __func__, hw->dch.dev.id,
+ __builtin_return_address(0), hw->open);
+ if (!hw->open) {
+ hfcsusb_stop_endpoint(hw, HFC_CHAN_D);
+ if (hw->fifos[HFCUSB_PCM_RX].pipe)
+ hfcsusb_stop_endpoint(hw, HFC_CHAN_E);
+ handle_led(hw, LED_POWER_ON);
+ }
+ module_put(THIS_MODULE);
+ break;
+ case CONTROL_CHANNEL:
+ err = channel_ctrl(hw, arg);
+ break;
+ default:
+ if (dch->debug & DEBUG_HW)
+ printk(KERN_DEBUG "%s: %s: unknown command %x\n",
+ hw->name, __func__, cmd);
+ return -EINVAL;
+ }
+ return err;
+}
+
+/*
+ * S0 TE state change event handler
+ */
+static void
+ph_state_te(struct dchannel *dch)
+{
+ struct hfcsusb *hw = dch->hw;
+
+ if (debug & DEBUG_HW) {
+ if (dch->state <= HFC_MAX_TE_LAYER1_STATE)
+ printk(KERN_DEBUG "%s: %s: %s\n", hw->name, __func__,
+ HFC_TE_LAYER1_STATES[dch->state]);
+ else
+ printk(KERN_DEBUG "%s: %s: TE F%d\n",
+ hw->name, __func__, dch->state);
+ }
+
+ switch (dch->state) {
+ case 0:
+ l1_event(dch->l1, HW_RESET_IND);
+ break;
+ case 3:
+ l1_event(dch->l1, HW_DEACT_IND);
+ break;
+ case 5:
+ case 8:
+ l1_event(dch->l1, ANYSIGNAL);
+ break;
+ case 6:
+ l1_event(dch->l1, INFO2);
+ break;
+ case 7:
+ l1_event(dch->l1, INFO4_P8);
+ break;
+ }
+ if (dch->state == 7)
+ handle_led(hw, LED_S0_ON);
+ else
+ handle_led(hw, LED_S0_OFF);
+}
+
+/*
+ * S0 NT state change event handler
+ */
+static void
+ph_state_nt(struct dchannel *dch)
+{
+ struct hfcsusb *hw = dch->hw;
+
+ if (debug & DEBUG_HW) {
+ if (dch->state <= HFC_MAX_NT_LAYER1_STATE)
+ printk(KERN_DEBUG "%s: %s: %s\n",
+ hw->name, __func__,
+ HFC_NT_LAYER1_STATES[dch->state]);
+
+ else
+ printk(KERN_INFO DRIVER_NAME "%s: %s: NT G%d\n",
+ hw->name, __func__, dch->state);
+ }
+
+ switch (dch->state) {
+ case (1):
+ test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+ test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
+ hw->nt_timer = 0;
+ hw->timers &= ~NT_ACTIVATION_TIMER;
+ handle_led(hw, LED_S0_OFF);
+ break;
+
+ case (2):
+ if (hw->nt_timer < 0) {
+ hw->nt_timer = 0;
+ hw->timers &= ~NT_ACTIVATION_TIMER;
+ hfcsusb_ph_command(dch->hw, HFC_L1_DEACTIVATE_NT);
+ } else {
+ hw->timers |= NT_ACTIVATION_TIMER;
+ hw->nt_timer = NT_T1_COUNT;
+ /* allow G2 -> G3 transition */
+ write_reg(hw, HFCUSB_STATES, 2 | HFCUSB_NT_G2_G3);
+ }
+ break;
+ case (3):
+ hw->nt_timer = 0;
+ hw->timers &= ~NT_ACTIVATION_TIMER;
+ test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+ _queue_data(&dch->dev.D, PH_ACTIVATE_IND,
+ MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
+ handle_led(hw, LED_S0_ON);
+ break;
+ case (4):
+ hw->nt_timer = 0;
+ hw->timers &= ~NT_ACTIVATION_TIMER;
+ break;
+ default:
+ break;
+ }
+ hfcsusb_ph_info(hw);
+}
+
+static void
+ph_state(struct dchannel *dch)
+{
+ struct hfcsusb *hw = dch->hw;
+
+ if (hw->protocol == ISDN_P_NT_S0)
+ ph_state_nt(dch);
+ else if (hw->protocol == ISDN_P_TE_S0)
+ ph_state_te(dch);
+}
+
+/*
+ * disable/enable BChannel for desired protocoll
+ */
+static int
+hfcsusb_setup_bch(struct bchannel *bch, int protocol)
+{
+ struct hfcsusb *hw = bch->hw;
+ __u8 conhdlc, sctrl, sctrl_r;
+
+ if (debug & DEBUG_HW)
+ printk(KERN_DEBUG "%s: %s: protocol %x-->%x B%d\n",
+ hw->name, __func__, bch->state, protocol,
+ bch->nr);
+
+ /* setup val for CON_HDLC */
+ conhdlc = 0;
+ if (protocol > ISDN_P_NONE)
+ conhdlc = 8; /* enable FIFO */
+
+ switch (protocol) {
+ case (-1): /* used for init */
+ bch->state = -1;
+ /* fall trough */
+ case (ISDN_P_NONE):
+ if (bch->state == ISDN_P_NONE)
+ return 0; /* already in idle state */
+ bch->state = ISDN_P_NONE;
+ clear_bit(FLG_HDLC, &bch->Flags);
+ clear_bit(FLG_TRANSPARENT, &bch->Flags);
+ break;
+ case (ISDN_P_B_RAW):
+ conhdlc |= 2;
+ bch->state = protocol;
+ set_bit(FLG_TRANSPARENT, &bch->Flags);
+ break;
+ case (ISDN_P_B_HDLC):
+ bch->state = protocol;
+ set_bit(FLG_HDLC, &bch->Flags);
+ break;
+ default:
+ if (debug & DEBUG_HW)
+ printk(KERN_DEBUG "%s: %s: prot not known %x\n",
+ hw->name, __func__, protocol);
+ return -ENOPROTOOPT;
+ }
+
+ if (protocol >= ISDN_P_NONE) {
+ write_reg(hw, HFCUSB_FIFO, (bch->nr == 1) ? 0 : 2);
+ write_reg(hw, HFCUSB_CON_HDLC, conhdlc);
+ write_reg(hw, HFCUSB_INC_RES_F, 2);
+ write_reg(hw, HFCUSB_FIFO, (bch->nr == 1) ? 1 : 3);
+ write_reg(hw, HFCUSB_CON_HDLC, conhdlc);
+ write_reg(hw, HFCUSB_INC_RES_F, 2);
+
+ sctrl = 0x40 + ((hw->protocol == ISDN_P_TE_S0) ? 0x00 : 0x04);
+ sctrl_r = 0x0;
+ if (test_bit(FLG_ACTIVE, &hw->bch[0].Flags)) {
+ sctrl |= 1;
+ sctrl_r |= 1;
+ }
+ if (test_bit(FLG_ACTIVE, &hw->bch[1].Flags)) {
+ sctrl |= 2;
+ sctrl_r |= 2;
+ }
+ write_reg(hw, HFCUSB_SCTRL, sctrl);
+ write_reg(hw, HFCUSB_SCTRL_R, sctrl_r);
+
+ if (protocol > ISDN_P_NONE)
+ handle_led(hw, (bch->nr == 1) ? LED_B1_ON : LED_B2_ON);
+ else
+ handle_led(hw, (bch->nr == 1) ? LED_B1_OFF :
+ LED_B2_OFF);
+ }
+ hfcsusb_ph_info(hw);
+ return 0;
+}
+
+static void
+hfcsusb_ph_command(struct hfcsusb *hw, u_char command)
+{
+ if (debug & DEBUG_HW)
+ printk(KERN_DEBUG "%s: %s: %x\n",
+ hw->name, __func__, command);
+
+ switch (command) {
+ case HFC_L1_ACTIVATE_TE:
+ /* force sending sending INFO1 */
+ write_reg(hw, HFCUSB_STATES, 0x14);
+ /* start l1 activation */
+ write_reg(hw, HFCUSB_STATES, 0x04);
+ break;
+
+ case HFC_L1_FORCE_DEACTIVATE_TE:
+ write_reg(hw, HFCUSB_STATES, 0x10);
+ write_reg(hw, HFCUSB_STATES, 0x03);
+ break;
+
+ case HFC_L1_ACTIVATE_NT:
+ if (hw->dch.state == 3)
+ _queue_data(&hw->dch.dev.D, PH_ACTIVATE_IND,
+ MISDN_ID_ANY, 0, NULL, GFP_ATOMIC);
+ else
+ write_reg(hw, HFCUSB_STATES, HFCUSB_ACTIVATE |
+ HFCUSB_DO_ACTION | HFCUSB_NT_G2_G3);
+ break;
+
+ case HFC_L1_DEACTIVATE_NT:
+ write_reg(hw, HFCUSB_STATES,
+ HFCUSB_DO_ACTION);
+ break;
+ }
+}
+
+/*
+ * Layer 1 B-channel hardware access
+ */
+static int
+channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = MISDN_CTRL_FILL_EMPTY;
+ break;
+ case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */
+ test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
+ if (debug & DEBUG_HW_OPEN)
+ printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d "
+ "off=%d)\n", __func__, bch->nr, !!cq->p1);
+ break;
+ default:
+ printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+/* collect data from incoming interrupt or isochron USB data */
+static void
+hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
+ int finish)
+{
+ struct hfcsusb *hw = fifo->hw;
+ struct sk_buff *rx_skb = NULL;
+ int maxlen = 0;
+ int fifon = fifo->fifonum;
+ int i;
+ int hdlc = 0;
+
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s: fifo(%i) len(%i) "
+ "dch(%p) bch(%p) ech(%p)\n",
+ hw->name, __func__, fifon, len,
+ fifo->dch, fifo->bch, fifo->ech);
+
+ if (!len)
+ return;
+
+ if ((!!fifo->dch + !!fifo->bch + !!fifo->ech) != 1) {
+ printk(KERN_DEBUG "%s: %s: undefined channel\n",
+ hw->name, __func__);
+ return;
+ }
+
+ spin_lock(&hw->lock);
+ if (fifo->dch) {
+ rx_skb = fifo->dch->rx_skb;
+ maxlen = fifo->dch->maxlen;
+ hdlc = 1;
+ }
+ if (fifo->bch) {
+ rx_skb = fifo->bch->rx_skb;
+ maxlen = fifo->bch->maxlen;
+ hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
+ }
+ if (fifo->ech) {
+ rx_skb = fifo->ech->rx_skb;
+ maxlen = fifo->ech->maxlen;
+ hdlc = 1;
+ }
+
+ if (!rx_skb) {
+ rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC);
+ if (rx_skb) {
+ if (fifo->dch)
+ fifo->dch->rx_skb = rx_skb;
+ if (fifo->bch)
+ fifo->bch->rx_skb = rx_skb;
+ if (fifo->ech)
+ fifo->ech->rx_skb = rx_skb;
+ skb_trim(rx_skb, 0);
+ } else {
+ printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n",
+ hw->name, __func__);
+ spin_unlock(&hw->lock);
+ return;
+ }
+ }
+
+ if (fifo->dch || fifo->ech) {
+ /* D/E-Channel SKB range check */
+ if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) {
+ printk(KERN_DEBUG "%s: %s: sbk mem exceeded "
+ "for fifo(%d) HFCUSB_D_RX\n",
+ hw->name, __func__, fifon);
+ skb_trim(rx_skb, 0);
+ spin_unlock(&hw->lock);
+ return;
+ }
+ } else if (fifo->bch) {
+ /* B-Channel SKB range check */
+ if ((rx_skb->len + len) >= (MAX_BCH_SIZE + 3)) {
+ printk(KERN_DEBUG "%s: %s: sbk mem exceeded "
+ "for fifo(%d) HFCUSB_B_RX\n",
+ hw->name, __func__, fifon);
+ skb_trim(rx_skb, 0);
+ spin_unlock(&hw->lock);
+ return;
+ }
+ }
+
+ memcpy(skb_put(rx_skb, len), data, len);
+
+ if (hdlc) {
+ /* we have a complete hdlc packet */
+ if (finish) {
+ if ((rx_skb->len > 3) &&
+ (!(rx_skb->data[rx_skb->len - 1]))) {
+ if (debug & DBG_HFC_FIFO_VERBOSE) {
+ printk(KERN_DEBUG "%s: %s: fifon(%i)"
+ " new RX len(%i): ",
+ hw->name, __func__, fifon,
+ rx_skb->len);
+ i = 0;
+ while (i < rx_skb->len)
+ printk("%02x ",
+ rx_skb->data[i++]);
+ printk("\n");
+ }
+
+ /* remove CRC & status */
+ skb_trim(rx_skb, rx_skb->len - 3);
+
+ if (fifo->dch)
+ recv_Dchannel(fifo->dch);
+ if (fifo->bch)
+ recv_Bchannel(fifo->bch);
+ if (fifo->ech)
+ recv_Echannel(fifo->ech,
+ &hw->dch);
+ } else {
+ if (debug & DBG_HFC_FIFO_VERBOSE) {
+ printk(KERN_DEBUG
+ "%s: CRC or minlen ERROR fifon(%i) "
+ "RX len(%i): ",
+ hw->name, fifon, rx_skb->len);
+ i = 0;
+ while (i < rx_skb->len)
+ printk("%02x ",
+ rx_skb->data[i++]);
+ printk("\n");
+ }
+ skb_trim(rx_skb, 0);
+ }
+ }
+ } else {
+ /* deliver transparent data to layer2 */
+ if (rx_skb->len >= poll)
+ recv_Bchannel(fifo->bch);
+ }
+ spin_unlock(&hw->lock);
+}
+
+void
+fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
+ void *buf, int num_packets, int packet_size, int interval,
+ usb_complete_t complete, void *context)
+{
+ int k;
+
+ usb_fill_bulk_urb(urb, dev, pipe, buf, packet_size * num_packets,
+ complete, context);
+
+ urb->number_of_packets = num_packets;
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->actual_length = 0;
+ urb->interval = interval;
+
+ for (k = 0; k < num_packets; k++) {
+ urb->iso_frame_desc[k].offset = packet_size * k;
+ urb->iso_frame_desc[k].length = packet_size;
+ urb->iso_frame_desc[k].actual_length = 0;
+ }
+}
+
+/* receive completion routine for all ISO tx fifos */
+static void
+rx_iso_complete(struct urb *urb)
+{
+ struct iso_urb *context_iso_urb = (struct iso_urb *) urb->context;
+ struct usb_fifo *fifo = context_iso_urb->owner_fifo;
+ struct hfcsusb *hw = fifo->hw;
+ int k, len, errcode, offset, num_isoc_packets, fifon, maxlen,
+ status, iso_status, i;
+ __u8 *buf;
+ static __u8 eof[8];
+ __u8 s0_state;
+
+ fifon = fifo->fifonum;
+ status = urb->status;
+
+ spin_lock(&hw->lock);
+ if (fifo->stop_gracefull) {
+ fifo->stop_gracefull = 0;
+ fifo->active = 0;
+ spin_unlock(&hw->lock);
+ return;
+ }
+ spin_unlock(&hw->lock);
+
+ /*
+ * ISO transfer only partially completed,
+ * look at individual frame status for details
+ */
+ if (status == -EXDEV) {
+ if (debug & DEBUG_HW)
+ printk(KERN_DEBUG "%s: %s: with -EXDEV "
+ "urb->status %d, fifonum %d\n",
+ hw->name, __func__, status, fifon);
+
+ /* clear status, so go on with ISO transfers */
+ status = 0;
+ }
+
+ s0_state = 0;
+ if (fifo->active && !status) {
+ num_isoc_packets = iso_packets[fifon];
+ maxlen = fifo->usb_packet_maxlen;
+
+ for (k = 0; k < num_isoc_packets; ++k) {
+ len = urb->iso_frame_desc[k].actual_length;
+ offset = urb->iso_frame_desc[k].offset;
+ buf = context_iso_urb->buffer + offset;
+ iso_status = urb->iso_frame_desc[k].status;
+
+ if (iso_status && (debug & DBG_HFC_FIFO_VERBOSE)) {
+ printk(KERN_DEBUG "%s: %s: "
+ "ISO packet %i, status: %i\n",
+ hw->name, __func__, k, iso_status);
+ }
+
+ /* USB data log for every D ISO in */
+ if ((fifon == HFCUSB_D_RX) &&
+ (debug & DBG_HFC_USB_VERBOSE)) {
+ printk(KERN_DEBUG
+ "%s: %s: %d (%d/%d) len(%d) ",
+ hw->name, __func__, urb->start_frame,
+ k, num_isoc_packets-1,
+ len);
+ for (i = 0; i < len; i++)
+ printk("%x ", buf[i]);
+ printk("\n");
+ }
+
+ if (!iso_status) {
+ if (fifo->last_urblen != maxlen) {
+ /*
+ * save fifo fill-level threshold bits
+ * to use them later in TX ISO URB
+ * completions
+ */
+ hw->threshold_mask = buf[1];
+
+ if (fifon == HFCUSB_D_RX)
+ s0_state = (buf[0] >> 4);
+
+ eof[fifon] = buf[0] & 1;
+ if (len > 2)
+ hfcsusb_rx_frame(fifo, buf + 2,
+ len - 2, (len < maxlen)
+ ? eof[fifon] : 0);
+ } else
+ hfcsusb_rx_frame(fifo, buf, len,
+ (len < maxlen) ?
+ eof[fifon] : 0);
+ fifo->last_urblen = len;
+ }
+ }
+
+ /* signal S0 layer1 state change */
+ if ((s0_state) && (hw->initdone) &&
+ (s0_state != hw->dch.state)) {
+ hw->dch.state = s0_state;
+ schedule_event(&hw->dch, FLG_PHCHANGE);
+ }
+
+ fill_isoc_urb(urb, fifo->hw->dev, fifo->pipe,
+ context_iso_urb->buffer, num_isoc_packets,
+ fifo->usb_packet_maxlen, fifo->intervall,
+ (usb_complete_t)rx_iso_complete, urb->context);
+ errcode = usb_submit_urb(urb, GFP_ATOMIC);
+ if (errcode < 0) {
+ if (debug & DEBUG_HW)
+ printk(KERN_DEBUG "%s: %s: error submitting "
+ "ISO URB: %d\n",
+ hw->name, __func__, errcode);
+ }
+ } else {
+ if (status && (debug & DBG_HFC_URB_INFO))
+ printk(KERN_DEBUG "%s: %s: rx_iso_complete : "
+ "urb->status %d, fifonum %d\n",
+ hw->name, __func__, status, fifon);
+ }
+}
+
+/* receive completion routine for all interrupt rx fifos */
+static void
+rx_int_complete(struct urb *urb)
+{
+ int len, status, i;
+ __u8 *buf, maxlen, fifon;
+ struct usb_fifo *fifo = (struct usb_fifo *) urb->context;
+ struct hfcsusb *hw = fifo->hw;
+ static __u8 eof[8];
+
+ spin_lock(&hw->lock);
+ if (fifo->stop_gracefull) {
+ fifo->stop_gracefull = 0;
+ fifo->active = 0;
+ spin_unlock(&hw->lock);
+ return;
+ }
+ spin_unlock(&hw->lock);
+
+ fifon = fifo->fifonum;
+ if ((!fifo->active) || (urb->status)) {
+ if (debug & DBG_HFC_URB_ERROR)
+ printk(KERN_DEBUG
+ "%s: %s: RX-Fifo %i is going down (%i)\n",
+ hw->name, __func__, fifon, urb->status);
+
+ fifo->urb->interval = 0; /* cancel automatic rescheduling */
+ return;
+ }
+ len = urb->actual_length;
+ buf = fifo->buffer;
+ maxlen = fifo->usb_packet_maxlen;
+
+ /* USB data log for every D INT in */
+ if ((fifon == HFCUSB_D_RX) && (debug & DBG_HFC_USB_VERBOSE)) {
+ printk(KERN_DEBUG "%s: %s: D RX INT len(%d) ",
+ hw->name, __func__, len);
+ for (i = 0; i < len; i++)
+ printk("%02x ", buf[i]);
+ printk("\n");
+ }
+
+ if (fifo->last_urblen != fifo->usb_packet_maxlen) {
+ /* the threshold mask is in the 2nd status byte */
+ hw->threshold_mask = buf[1];
+
+ /* signal S0 layer1 state change */
+ if (hw->initdone && ((buf[0] >> 4) != hw->dch.state)) {
+ hw->dch.state = (buf[0] >> 4);
+ schedule_event(&hw->dch, FLG_PHCHANGE);
+ }
+
+ eof[fifon] = buf[0] & 1;
+ /* if we have more than the 2 status bytes -> collect data */
+ if (len > 2)
+ hfcsusb_rx_frame(fifo, buf + 2,
+ urb->actual_length - 2,
+ (len < maxlen) ? eof[fifon] : 0);
+ } else {
+ hfcsusb_rx_frame(fifo, buf, urb->actual_length,
+ (len < maxlen) ? eof[fifon] : 0);
+ }
+ fifo->last_urblen = urb->actual_length;
+
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status) {
+ if (debug & DEBUG_HW)
+ printk(KERN_DEBUG "%s: %s: error resubmitting USB\n",
+ hw->name, __func__);
+ }
+}
+
+/* transmit completion routine for all ISO tx fifos */
+static void
+tx_iso_complete(struct urb *urb)
+{
+ struct iso_urb *context_iso_urb = (struct iso_urb *) urb->context;
+ struct usb_fifo *fifo = context_iso_urb->owner_fifo;
+ struct hfcsusb *hw = fifo->hw;
+ struct sk_buff *tx_skb;
+ int k, tx_offset, num_isoc_packets, sink, remain, current_len,
+ errcode, hdlc, i;
+ int *tx_idx;
+ int frame_complete, fifon, status;
+ __u8 threshbit;
+
+ spin_lock(&hw->lock);
+ if (fifo->stop_gracefull) {
+ fifo->stop_gracefull = 0;
+ fifo->active = 0;
+ spin_unlock(&hw->lock);
+ return;
+ }
+
+ if (fifo->dch) {
+ tx_skb = fifo->dch->tx_skb;
+ tx_idx = &fifo->dch->tx_idx;
+ hdlc = 1;
+ } else if (fifo->bch) {
+ tx_skb = fifo->bch->tx_skb;
+ tx_idx = &fifo->bch->tx_idx;
+ hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags);
+ } else {
+ printk(KERN_DEBUG "%s: %s: neither BCH nor DCH\n",
+ hw->name, __func__);
+ spin_unlock(&hw->lock);
+ return;
+ }
+
+ fifon = fifo->fifonum;
+ status = urb->status;
+
+ tx_offset = 0;
+
+ /*
+ * ISO transfer only partially completed,
+ * look at individual frame status for details
+ */
+ if (status == -EXDEV) {
+ if (debug & DBG_HFC_URB_ERROR)
+ printk(KERN_DEBUG "%s: %s: "
+ "-EXDEV (%i) fifon (%d)\n",
+ hw->name, __func__, status, fifon);
+
+ /* clear status, so go on with ISO transfers */
+ status = 0;
+ }
+
+ if (fifo->active && !status) {
+ /* is FifoFull-threshold set for our channel? */
+ threshbit = (hw->threshold_mask & (1 << fifon));
+ num_isoc_packets = iso_packets[fifon];
+
+ /* predict dataflow to avoid fifo overflow */
+ if (fifon >= HFCUSB_D_TX)
+ sink = (threshbit) ? SINK_DMIN : SINK_DMAX;
+ else
+ sink = (threshbit) ? SINK_MIN : SINK_MAX;
+ fill_isoc_urb(urb, fifo->hw->dev, fifo->pipe,
+ context_iso_urb->buffer, num_isoc_packets,
+ fifo->usb_packet_maxlen, fifo->intervall,
+ (usb_complete_t)tx_iso_complete, urb->context);
+ memset(context_iso_urb->buffer, 0,
+ sizeof(context_iso_urb->buffer));
+ frame_complete = 0;
+
+ for (k = 0; k < num_isoc_packets; ++k) {
+ /* analyze tx success of previous ISO packets */
+ if (debug & DBG_HFC_URB_ERROR) {
+ errcode = urb->iso_frame_desc[k].status;
+ if (errcode) {
+ printk(KERN_DEBUG "%s: %s: "
+ "ISO packet %i, status: %i\n",
+ hw->name, __func__, k, errcode);
+ }
+ }
+
+ /* Generate next ISO Packets */
+ if (tx_skb)
+ remain = tx_skb->len - *tx_idx;
+ else
+ remain = 0;
+
+ if (remain > 0) {
+ fifo->bit_line -= sink;
+ current_len = (0 - fifo->bit_line) / 8;
+ if (current_len > 14)
+ current_len = 14;
+ if (current_len < 0)
+ current_len = 0;
+ if (remain < current_len)
+ current_len = remain;
+
+ /* how much bit do we put on the line? */
+ fifo->bit_line += current_len * 8;
+
+ context_iso_urb->buffer[tx_offset] = 0;
+ if (current_len == remain) {
+ if (hdlc) {
+ /* signal frame completion */
+ context_iso_urb->
+ buffer[tx_offset] = 1;
+ /* add 2 byte flags and 16bit
+ * CRC at end of ISDN frame */
+ fifo->bit_line += 32;
+ }
+ frame_complete = 1;
+ }
+
+ /* copy tx data to iso-urb buffer */
+ memcpy(context_iso_urb->buffer + tx_offset + 1,
+ (tx_skb->data + *tx_idx), current_len);
+ *tx_idx += current_len;
+
+ urb->iso_frame_desc[k].offset = tx_offset;
+ urb->iso_frame_desc[k].length = current_len + 1;
+
+ /* USB data log for every D ISO out */
+ if ((fifon == HFCUSB_D_RX) &&
+ (debug & DBG_HFC_USB_VERBOSE)) {
+ printk(KERN_DEBUG
+ "%s: %s (%d/%d) offs(%d) len(%d) ",
+ hw->name, __func__,
+ k, num_isoc_packets-1,
+ urb->iso_frame_desc[k].offset,
+ urb->iso_frame_desc[k].length);
+
+ for (i = urb->iso_frame_desc[k].offset;
+ i < (urb->iso_frame_desc[k].offset
+ + urb->iso_frame_desc[k].length);
+ i++)
+ printk("%x ",
+ context_iso_urb->buffer[i]);
+
+ printk(" skb->len(%i) tx-idx(%d)\n",
+ tx_skb->len, *tx_idx);
+ }
+
+ tx_offset += (current_len + 1);
+ } else {
+ urb->iso_frame_desc[k].offset = tx_offset++;
+ urb->iso_frame_desc[k].length = 1;
+ /* we lower data margin every msec */
+ fifo->bit_line -= sink;
+ if (fifo->bit_line < BITLINE_INF)
+ fifo->bit_line = BITLINE_INF;
+ }
+
+ if (frame_complete) {
+ frame_complete = 0;
+
+ if (debug & DBG_HFC_FIFO_VERBOSE) {
+ printk(KERN_DEBUG "%s: %s: "
+ "fifon(%i) new TX len(%i): ",
+ hw->name, __func__,
+ fifon, tx_skb->len);
+ i = 0;
+ while (i < tx_skb->len)
+ printk("%02x ",
+ tx_skb->data[i++]);
+ printk("\n");
+ }
+
+ dev_kfree_skb(tx_skb);
+ tx_skb = NULL;
+ if (fifo->dch && get_next_dframe(fifo->dch))
+ tx_skb = fifo->dch->tx_skb;
+ else if (fifo->bch &&
+ get_next_bframe(fifo->bch)) {
+ if (test_bit(FLG_TRANSPARENT,
+ &fifo->bch->Flags))
+ confirm_Bsend(fifo->bch);
+ tx_skb = fifo->bch->tx_skb;
+ }
+ }
+ }
+ errcode = usb_submit_urb(urb, GFP_ATOMIC);
+ if (errcode < 0) {
+ if (debug & DEBUG_HW)
+ printk(KERN_DEBUG
+ "%s: %s: error submitting ISO URB: %d \n",
+ hw->name, __func__, errcode);
+ }
+
+ /*
+ * abuse DChannel tx iso completion to trigger NT mode state
+ * changes tx_iso_complete is assumed to be called every
+ * fifo->intervall (ms)
+ */
+ if ((fifon == HFCUSB_D_TX) && (hw->protocol == ISDN_P_NT_S0)
+ && (hw->timers & NT_ACTIVATION_TIMER)) {
+ if ((--hw->nt_timer) < 0)
+ schedule_event(&hw->dch, FLG_PHCHANGE);
+ }
+
+ } else {
+ if (status && (debug & DBG_HFC_URB_ERROR))
+ printk(KERN_DEBUG "%s: %s: urb->status %s (%i)"
+ "fifonum=%d\n",
+ hw->name, __func__,
+ symbolic(urb_errlist, status), status, fifon);
+ }
+ spin_unlock(&hw->lock);
+}
+
+/*
+ * allocs urbs and start isoc transfer with two pending urbs to avoid
+ * gaps in the transfer chain
+ */
+static int
+start_isoc_chain(struct usb_fifo *fifo, int num_packets_per_urb,
+ usb_complete_t complete, int packet_size)
+{
+ struct hfcsusb *hw = fifo->hw;
+ int i, k, errcode;
+
+ if (debug)
+ printk(KERN_DEBUG "%s: %s: fifo %i\n",
+ hw->name, __func__, fifo->fifonum);
+
+ /* allocate Memory for Iso out Urbs */
+ for (i = 0; i < 2; i++) {
+ if (!(fifo->iso[i].urb)) {
+ fifo->iso[i].urb =
+ usb_alloc_urb(num_packets_per_urb, GFP_KERNEL);
+ if (!(fifo->iso[i].urb)) {
+ printk(KERN_DEBUG
+ "%s: %s: alloc urb for fifo %i failed",
+ hw->name, __func__, fifo->fifonum);
+ }
+ fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo;
+ fifo->iso[i].indx = i;
+
+ /* Init the first iso */
+ if (ISO_BUFFER_SIZE >=
+ (fifo->usb_packet_maxlen *
+ num_packets_per_urb)) {
+ fill_isoc_urb(fifo->iso[i].urb,
+ fifo->hw->dev, fifo->pipe,
+ fifo->iso[i].buffer,
+ num_packets_per_urb,
+ fifo->usb_packet_maxlen,
+ fifo->intervall, complete,
+ &fifo->iso[i]);
+ memset(fifo->iso[i].buffer, 0,
+ sizeof(fifo->iso[i].buffer));
+
+ for (k = 0; k < num_packets_per_urb; k++) {
+ fifo->iso[i].urb->
+ iso_frame_desc[k].offset =
+ k * packet_size;
+ fifo->iso[i].urb->
+ iso_frame_desc[k].length =
+ packet_size;
+ }
+ } else {
+ printk(KERN_DEBUG
+ "%s: %s: ISO Buffer size to small!\n",
+ hw->name, __func__);
+ }
+ }
+ fifo->bit_line = BITLINE_INF;
+
+ errcode = usb_submit_urb(fifo->iso[i].urb, GFP_KERNEL);
+ fifo->active = (errcode >= 0) ? 1 : 0;
+ fifo->stop_gracefull = 0;
+ if (errcode < 0) {
+ printk(KERN_DEBUG "%s: %s: %s URB nr:%d\n",
+ hw->name, __func__,
+ symbolic(urb_errlist, errcode), i);
+ }
+ }
+ return fifo->active;
+}
+
+static void
+stop_iso_gracefull(struct usb_fifo *fifo)
+{
+ struct hfcsusb *hw = fifo->hw;
+ int i, timeout;
+ u_long flags;
+
+ for (i = 0; i < 2; i++) {
+ spin_lock_irqsave(&hw->lock, flags);
+ if (debug)
+ printk(KERN_DEBUG "%s: %s for fifo %i.%i\n",
+ hw->name, __func__, fifo->fifonum, i);
+ fifo->stop_gracefull = 1;
+ spin_unlock_irqrestore(&hw->lock, flags);
+ }
+
+ for (i = 0; i < 2; i++) {
+ timeout = 3;
+ while (fifo->stop_gracefull && timeout--)
+ schedule_timeout_interruptible((HZ/1000)*16);
+ if (debug && fifo->stop_gracefull)
+ printk(KERN_DEBUG "%s: ERROR %s for fifo %i.%i\n",
+ hw->name, __func__, fifo->fifonum, i);
+ }
+}
+
+static void
+stop_int_gracefull(struct usb_fifo *fifo)
+{
+ struct hfcsusb *hw = fifo->hw;
+ int timeout;
+ u_long flags;
+
+ spin_lock_irqsave(&hw->lock, flags);
+ if (debug)
+ printk(KERN_DEBUG "%s: %s for fifo %i\n",
+ hw->name, __func__, fifo->fifonum);
+ fifo->stop_gracefull = 1;
+ spin_unlock_irqrestore(&hw->lock, flags);
+
+ timeout = 3;
+ while (fifo->stop_gracefull && timeout--)
+ schedule_timeout_interruptible((HZ/1000)*3);
+ if (debug && fifo->stop_gracefull)
+ printk(KERN_DEBUG "%s: ERROR %s for fifo %i\n",
+ hw->name, __func__, fifo->fifonum);
+}
+
+/* start the interrupt transfer for the given fifo */
+static void
+start_int_fifo(struct usb_fifo *fifo)
+{
+ struct hfcsusb *hw = fifo->hw;
+ int errcode;
+
+ if (debug)
+ printk(KERN_DEBUG "%s: %s: INT IN fifo:%d\n",
+ hw->name, __func__, fifo->fifonum);
+
+ if (!fifo->urb) {
+ fifo->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!fifo->urb)
+ return;
+ }
+ usb_fill_int_urb(fifo->urb, fifo->hw->dev, fifo->pipe,
+ fifo->buffer, fifo->usb_packet_maxlen,
+ (usb_complete_t)rx_int_complete, fifo, fifo->intervall);
+ fifo->active = 1;
+ fifo->stop_gracefull = 0;
+ errcode = usb_submit_urb(fifo->urb, GFP_KERNEL);
+ if (errcode) {
+ printk(KERN_DEBUG "%s: %s: submit URB: status:%i\n",
+ hw->name, __func__, errcode);
+ fifo->active = 0;
+ }
+}
+
+static void
+setPortMode(struct hfcsusb *hw)
+{
+ if (debug & DEBUG_HW)
+ printk(KERN_DEBUG "%s: %s %s\n", hw->name, __func__,
+ (hw->protocol == ISDN_P_TE_S0) ? "TE" : "NT");
+
+ if (hw->protocol == ISDN_P_TE_S0) {
+ write_reg(hw, HFCUSB_SCTRL, 0x40);
+ write_reg(hw, HFCUSB_SCTRL_E, 0x00);
+ write_reg(hw, HFCUSB_CLKDEL, CLKDEL_TE);
+ write_reg(hw, HFCUSB_STATES, 3 | 0x10);
+ write_reg(hw, HFCUSB_STATES, 3);
+ } else {
+ write_reg(hw, HFCUSB_SCTRL, 0x44);
+ write_reg(hw, HFCUSB_SCTRL_E, 0x09);
+ write_reg(hw, HFCUSB_CLKDEL, CLKDEL_NT);
+ write_reg(hw, HFCUSB_STATES, 1 | 0x10);
+ write_reg(hw, HFCUSB_STATES, 1);
+ }
+}
+
+static void
+reset_hfcsusb(struct hfcsusb *hw)
+{
+ struct usb_fifo *fifo;
+ int i;
+
+ if (debug & DEBUG_HW)
+ printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
+
+ /* do Chip reset */
+ write_reg(hw, HFCUSB_CIRM, 8);
+
+ /* aux = output, reset off */
+ write_reg(hw, HFCUSB_CIRM, 0x10);
+
+ /* set USB_SIZE to match the wMaxPacketSize for INT or BULK transfers */
+ write_reg(hw, HFCUSB_USB_SIZE, (hw->packet_size / 8) |
+ ((hw->packet_size / 8) << 4));
+
+ /* set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers */
+ write_reg(hw, HFCUSB_USB_SIZE_I, hw->iso_packet_size);
+
+ /* enable PCM/GCI master mode */
+ write_reg(hw, HFCUSB_MST_MODE1, 0); /* set default values */
+ write_reg(hw, HFCUSB_MST_MODE0, 1); /* enable master mode */
+
+ /* init the fifos */
+ write_reg(hw, HFCUSB_F_THRES,
+ (HFCUSB_TX_THRESHOLD / 8) | ((HFCUSB_RX_THRESHOLD / 8) << 4));
+
+ fifo = hw->fifos;
+ for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
+ write_reg(hw, HFCUSB_FIFO, i); /* select the desired fifo */
+ fifo[i].max_size =
+ (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN;
+ fifo[i].last_urblen = 0;
+
+ /* set 2 bit for D- & E-channel */
+ write_reg(hw, HFCUSB_HDLC_PAR, ((i <= HFCUSB_B2_RX) ? 0 : 2));
+
+ /* enable all fifos */
+ if (i == HFCUSB_D_TX)
+ write_reg(hw, HFCUSB_CON_HDLC,
+ (hw->protocol == ISDN_P_NT_S0) ? 0x08 : 0x09);
+ else
+ write_reg(hw, HFCUSB_CON_HDLC, 0x08);
+ write_reg(hw, HFCUSB_INC_RES_F, 2); /* reset the fifo */
+ }
+
+ write_reg(hw, HFCUSB_SCTRL_R, 0); /* disable both B receivers */
+ handle_led(hw, LED_POWER_ON);
+}
+
+/* start USB data pipes dependand on device's endpoint configuration */
+static void
+hfcsusb_start_endpoint(struct hfcsusb *hw, int channel)
+{
+ /* quick check if endpoint already running */
+ if ((channel == HFC_CHAN_D) && (hw->fifos[HFCUSB_D_RX].active))
+ return;
+ if ((channel == HFC_CHAN_B1) && (hw->fifos[HFCUSB_B1_RX].active))
+ return;
+ if ((channel == HFC_CHAN_B2) && (hw->fifos[HFCUSB_B2_RX].active))
+ return;
+ if ((channel == HFC_CHAN_E) && (hw->fifos[HFCUSB_PCM_RX].active))
+ return;
+
+ /* start rx endpoints using USB INT IN method */
+ if (hw->cfg_used == CNF_3INT3ISO || hw->cfg_used == CNF_4INT3ISO)
+ start_int_fifo(hw->fifos + channel*2 + 1);
+
+ /* start rx endpoints using USB ISO IN method */
+ if (hw->cfg_used == CNF_3ISO3ISO || hw->cfg_used == CNF_4ISO3ISO) {
+ switch (channel) {
+ case HFC_CHAN_D:
+ start_isoc_chain(hw->fifos + HFCUSB_D_RX,
+ ISOC_PACKETS_D,
+ (usb_complete_t)rx_iso_complete,
+ 16);
+ break;
+ case HFC_CHAN_E:
+ start_isoc_chain(hw->fifos + HFCUSB_PCM_RX,
+ ISOC_PACKETS_D,
+ (usb_complete_t)rx_iso_complete,
+ 16);
+ break;
+ case HFC_CHAN_B1:
+ start_isoc_chain(hw->fifos + HFCUSB_B1_RX,
+ ISOC_PACKETS_B,
+ (usb_complete_t)rx_iso_complete,
+ 16);
+ break;
+ case HFC_CHAN_B2:
+ start_isoc_chain(hw->fifos + HFCUSB_B2_RX,
+ ISOC_PACKETS_B,
+ (usb_complete_t)rx_iso_complete,
+ 16);
+ break;
+ }
+ }
+
+ /* start tx endpoints using USB ISO OUT method */
+ switch (channel) {
+ case HFC_CHAN_D:
+ start_isoc_chain(hw->fifos + HFCUSB_D_TX,
+ ISOC_PACKETS_B,
+ (usb_complete_t)tx_iso_complete, 1);
+ break;
+ case HFC_CHAN_B1:
+ start_isoc_chain(hw->fifos + HFCUSB_B1_TX,
+ ISOC_PACKETS_D,
+ (usb_complete_t)tx_iso_complete, 1);
+ break;
+ case HFC_CHAN_B2:
+ start_isoc_chain(hw->fifos + HFCUSB_B2_TX,
+ ISOC_PACKETS_B,
+ (usb_complete_t)tx_iso_complete, 1);
+ break;
+ }
+}
+
+/* stop USB data pipes dependand on device's endpoint configuration */
+static void
+hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel)
+{
+ /* quick check if endpoint currently running */
+ if ((channel == HFC_CHAN_D) && (!hw->fifos[HFCUSB_D_RX].active))
+ return;
+ if ((channel == HFC_CHAN_B1) && (!hw->fifos[HFCUSB_B1_RX].active))
+ return;
+ if ((channel == HFC_CHAN_B2) && (!hw->fifos[HFCUSB_B2_RX].active))
+ return;
+ if ((channel == HFC_CHAN_E) && (!hw->fifos[HFCUSB_PCM_RX].active))
+ return;
+
+ /* rx endpoints using USB INT IN method */
+ if (hw->cfg_used == CNF_3INT3ISO || hw->cfg_used == CNF_4INT3ISO)
+ stop_int_gracefull(hw->fifos + channel*2 + 1);
+
+ /* rx endpoints using USB ISO IN method */
+ if (hw->cfg_used == CNF_3ISO3ISO || hw->cfg_used == CNF_4ISO3ISO)
+ stop_iso_gracefull(hw->fifos + channel*2 + 1);
+
+ /* tx endpoints using USB ISO OUT method */
+ if (channel != HFC_CHAN_E)
+ stop_iso_gracefull(hw->fifos + channel*2);
+}
+
+
+/* Hardware Initialization */
+int
+setup_hfcsusb(struct hfcsusb *hw)
+{
+ int err;
+ u_char b;
+
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
+
+ /* check the chip id */
+ if (read_reg_atomic(hw, HFCUSB_CHIP_ID, &b) != 1) {
+ printk(KERN_DEBUG "%s: %s: cannot read chip id\n",
+ hw->name, __func__);
+ return 1;
+ }
+ if (b != HFCUSB_CHIPID) {
+ printk(KERN_DEBUG "%s: %s: Invalid chip id 0x%02x\n",
+ hw->name, __func__, b);
+ return 1;
+ }
+
+ /* first set the needed config, interface and alternate */
+ err = usb_set_interface(hw->dev, hw->if_used, hw->alt_used);
+
+ hw->led_state = 0;
+
+ /* init the background machinery for control requests */
+ hw->ctrl_read.bRequestType = 0xc0;
+ hw->ctrl_read.bRequest = 1;
+ hw->ctrl_read.wLength = cpu_to_le16(1);
+ hw->ctrl_write.bRequestType = 0x40;
+ hw->ctrl_write.bRequest = 0;
+ hw->ctrl_write.wLength = 0;
+ usb_fill_control_urb(hw->ctrl_urb, hw->dev, hw->ctrl_out_pipe,
+ (u_char *)&hw->ctrl_write, NULL, 0,
+ (usb_complete_t)ctrl_complete, hw);
+
+ reset_hfcsusb(hw);
+ return 0;
+}
+
+static void
+release_hw(struct hfcsusb *hw)
+{
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
+
+ /*
+ * stop all endpoints gracefully
+ * TODO: mISDN_core should generate CLOSE_CHANNEL
+ * signals after calling mISDN_unregister_device()
+ */
+ hfcsusb_stop_endpoint(hw, HFC_CHAN_D);
+ hfcsusb_stop_endpoint(hw, HFC_CHAN_B1);
+ hfcsusb_stop_endpoint(hw, HFC_CHAN_B2);
+ if (hw->fifos[HFCUSB_PCM_RX].pipe)
+ hfcsusb_stop_endpoint(hw, HFC_CHAN_E);
+ if (hw->protocol == ISDN_P_TE_S0)
+ l1_event(hw->dch.l1, CLOSE_CHANNEL);
+
+ mISDN_unregister_device(&hw->dch.dev);
+ mISDN_freebchannel(&hw->bch[1]);
+ mISDN_freebchannel(&hw->bch[0]);
+ mISDN_freedchannel(&hw->dch);
+
+ if (hw->ctrl_urb) {
+ usb_kill_urb(hw->ctrl_urb);
+ usb_free_urb(hw->ctrl_urb);
+ hw->ctrl_urb = NULL;
+ }
+
+ if (hw->intf)
+ usb_set_intfdata(hw->intf, NULL);
+ list_del(&hw->list);
+ kfree(hw);
+ hw = NULL;
+}
+
+static void
+deactivate_bchannel(struct bchannel *bch)
+{
+ struct hfcsusb *hw = bch->hw;
+ u_long flags;
+
+ if (bch->debug & DEBUG_HW)
+ printk(KERN_DEBUG "%s: %s: bch->nr(%i)\n",
+ hw->name, __func__, bch->nr);
+
+ spin_lock_irqsave(&hw->lock, flags);
+ if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
+ dev_kfree_skb(bch->next_skb);
+ bch->next_skb = NULL;
+ }
+ if (bch->tx_skb) {
+ dev_kfree_skb(bch->tx_skb);
+ bch->tx_skb = NULL;
+ }
+ bch->tx_idx = 0;
+ if (bch->rx_skb) {
+ dev_kfree_skb(bch->rx_skb);
+ bch->rx_skb = NULL;
+ }
+ clear_bit(FLG_ACTIVE, &bch->Flags);
+ clear_bit(FLG_TX_BUSY, &bch->Flags);
+ spin_unlock_irqrestore(&hw->lock, flags);
+ hfcsusb_setup_bch(bch, ISDN_P_NONE);
+ hfcsusb_stop_endpoint(hw, bch->nr);
+}
+
+/*
+ * Layer 1 B-channel hardware access
+ */
+static int
+hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ int ret = -EINVAL;
+
+ if (bch->debug & DEBUG_HW)
+ printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg);
+
+ switch (cmd) {
+ case HW_TESTRX_RAW:
+ case HW_TESTRX_HDLC:
+ case HW_TESTRX_OFF:
+ ret = -EINVAL;
+ break;
+
+ case CLOSE_CHANNEL:
+ test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ if (test_bit(FLG_ACTIVE, &bch->Flags))
+ deactivate_bchannel(bch);
+ ch->protocol = ISDN_P_NONE;
+ ch->peer = NULL;
+ module_put(THIS_MODULE);
+ ret = 0;
+ break;
+ case CONTROL_CHANNEL:
+ ret = channel_bctrl(bch, arg);
+ break;
+ default:
+ printk(KERN_WARNING "%s: unknown prim(%x)\n",
+ __func__, cmd);
+ }
+ return ret;
+}
+
+static int
+setup_instance(struct hfcsusb *hw, struct device *parent)
+{
+ u_long flags;
+ int err, i;
+
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
+
+ spin_lock_init(&hw->ctrl_lock);
+ spin_lock_init(&hw->lock);
+
+ mISDN_initdchannel(&hw->dch, MAX_DFRAME_LEN_L1, ph_state);
+ hw->dch.debug = debug & 0xFFFF;
+ hw->dch.hw = hw;
+ hw->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0);
+ hw->dch.dev.D.send = hfcusb_l2l1D;
+ hw->dch.dev.D.ctrl = hfc_dctrl;
+
+ /* enable E-Channel logging */
+ if (hw->fifos[HFCUSB_PCM_RX].pipe)
+ mISDN_initdchannel(&hw->ech, MAX_DFRAME_LEN_L1, NULL);
+
+ hw->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
+ hw->dch.dev.nrbchan = 2;
+ for (i = 0; i < 2; i++) {
+ hw->bch[i].nr = i + 1;
+ set_channelmap(i + 1, hw->dch.dev.channelmap);
+ hw->bch[i].debug = debug;
+ mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM);
+ hw->bch[i].hw = hw;
+ hw->bch[i].ch.send = hfcusb_l2l1B;
+ hw->bch[i].ch.ctrl = hfc_bctrl;
+ hw->bch[i].ch.nr = i + 1;
+ list_add(&hw->bch[i].ch.list, &hw->dch.dev.bchannels);
+ }
+
+ hw->fifos[HFCUSB_B1_TX].bch = &hw->bch[0];
+ hw->fifos[HFCUSB_B1_RX].bch = &hw->bch[0];
+ hw->fifos[HFCUSB_B2_TX].bch = &hw->bch[1];
+ hw->fifos[HFCUSB_B2_RX].bch = &hw->bch[1];
+ hw->fifos[HFCUSB_D_TX].dch = &hw->dch;
+ hw->fifos[HFCUSB_D_RX].dch = &hw->dch;
+ hw->fifos[HFCUSB_PCM_RX].ech = &hw->ech;
+ hw->fifos[HFCUSB_PCM_TX].ech = &hw->ech;
+
+ err = setup_hfcsusb(hw);
+ if (err)
+ goto out;
+
+ snprintf(hw->name, MISDN_MAX_IDLEN - 1, "%s.%d", DRIVER_NAME,
+ hfcsusb_cnt + 1);
+ printk(KERN_INFO "%s: registered as '%s'\n",
+ DRIVER_NAME, hw->name);
+
+ err = mISDN_register_device(&hw->dch.dev, parent, hw->name);
+ if (err)
+ goto out;
+
+ hfcsusb_cnt++;
+ write_lock_irqsave(&HFClock, flags);
+ list_add_tail(&hw->list, &HFClist);
+ write_unlock_irqrestore(&HFClock, flags);
+ return 0;
+
+out:
+ mISDN_freebchannel(&hw->bch[1]);
+ mISDN_freebchannel(&hw->bch[0]);
+ mISDN_freedchannel(&hw->dch);
+ kfree(hw);
+ return err;
+}
+
+static int
+hfcsusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct hfcsusb *hw;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_host_interface *iface = intf->cur_altsetting;
+ struct usb_host_interface *iface_used = NULL;
+ struct usb_host_endpoint *ep;
+ struct hfcsusb_vdata *driver_info;
+ int ifnum = iface->desc.bInterfaceNumber, i, idx, alt_idx,
+ probe_alt_setting, vend_idx, cfg_used, *vcf, attr, cfg_found,
+ ep_addr, cmptbl[16], small_match, iso_packet_size, packet_size,
+ alt_used = 0;
+
+ vend_idx = 0xffff;
+ for (i = 0; hfcsusb_idtab[i].idVendor; i++) {
+ if ((le16_to_cpu(dev->descriptor.idVendor)
+ == hfcsusb_idtab[i].idVendor) &&
+ (le16_to_cpu(dev->descriptor.idProduct)
+ == hfcsusb_idtab[i].idProduct)) {
+ vend_idx = i;
+ continue;
+ }
+ }
+
+ printk(KERN_DEBUG
+ "%s: interface(%d) actalt(%d) minor(%d) vend_idx(%d)\n",
+ __func__, ifnum, iface->desc.bAlternateSetting,
+ intf->minor, vend_idx);
+
+ if (vend_idx == 0xffff) {
+ printk(KERN_WARNING
+ "%s: no valid vendor found in USB descriptor\n",
+ __func__);
+ return -EIO;
+ }
+ /* if vendor and product ID is OK, start probing alternate settings */
+ alt_idx = 0;
+ small_match = -1;
+
+ /* default settings */
+ iso_packet_size = 16;
+ packet_size = 64;
+
+ while (alt_idx < intf->num_altsetting) {
+ iface = intf->altsetting + alt_idx;
+ probe_alt_setting = iface->desc.bAlternateSetting;
+ cfg_used = 0;
+
+ while (validconf[cfg_used][0]) {
+ cfg_found = 1;
+ vcf = validconf[cfg_used];
+ ep = iface->endpoint;
+ memcpy(cmptbl, vcf, 16 * sizeof(int));
+
+ /* check for all endpoints in this alternate setting */
+ for (i = 0; i < iface->desc.bNumEndpoints; i++) {
+ ep_addr = ep->desc.bEndpointAddress;
+
+ /* get endpoint base */
+ idx = ((ep_addr & 0x7f) - 1) * 2;
+ if (ep_addr & 0x80)
+ idx++;
+ attr = ep->desc.bmAttributes;
+
+ if (cmptbl[idx] != EP_NOP) {
+ if (cmptbl[idx] == EP_NUL)
+ cfg_found = 0;
+ if (attr == USB_ENDPOINT_XFER_INT
+ && cmptbl[idx] == EP_INT)
+ cmptbl[idx] = EP_NUL;
+ if (attr == USB_ENDPOINT_XFER_BULK
+ && cmptbl[idx] == EP_BLK)
+ cmptbl[idx] = EP_NUL;
+ if (attr == USB_ENDPOINT_XFER_ISOC
+ && cmptbl[idx] == EP_ISO)
+ cmptbl[idx] = EP_NUL;
+
+ if (attr == USB_ENDPOINT_XFER_INT &&
+ ep->desc.bInterval < vcf[17]) {
+ cfg_found = 0;
+ }
+ }
+ ep++;
+ }
+
+ for (i = 0; i < 16; i++)
+ if (cmptbl[i] != EP_NOP && cmptbl[i] != EP_NUL)
+ cfg_found = 0;
+
+ if (cfg_found) {
+ if (small_match < cfg_used) {
+ small_match = cfg_used;
+ alt_used = probe_alt_setting;
+ iface_used = iface;
+ }
+ }
+ cfg_used++;
+ }
+ alt_idx++;
+ } /* (alt_idx < intf->num_altsetting) */
+
+ /* not found a valid USB Ta Endpoint config */
+ if (small_match == -1)
+ return -EIO;
+
+ iface = iface_used;
+ hw = kzalloc(sizeof(struct hfcsusb), GFP_KERNEL);
+ if (!hw)
+ return -ENOMEM; /* got no mem */
+ snprintf(hw->name, MISDN_MAX_IDLEN - 1, "%s", DRIVER_NAME);
+
+ ep = iface->endpoint;
+ vcf = validconf[small_match];
+
+ for (i = 0; i < iface->desc.bNumEndpoints; i++) {
+ struct usb_fifo *f;
+
+ ep_addr = ep->desc.bEndpointAddress;
+ /* get endpoint base */
+ idx = ((ep_addr & 0x7f) - 1) * 2;
+ if (ep_addr & 0x80)
+ idx++;
+ f = &hw->fifos[idx & 7];
+
+ /* init Endpoints */
+ if (vcf[idx] == EP_NOP || vcf[idx] == EP_NUL) {
+ ep++;
+ continue;
+ }
+ switch (ep->desc.bmAttributes) {
+ case USB_ENDPOINT_XFER_INT:
+ f->pipe = usb_rcvintpipe(dev,
+ ep->desc.bEndpointAddress);
+ f->usb_transfer_mode = USB_INT;
+ packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ if (ep_addr & 0x80)
+ f->pipe = usb_rcvbulkpipe(dev,
+ ep->desc.bEndpointAddress);
+ else
+ f->pipe = usb_sndbulkpipe(dev,
+ ep->desc.bEndpointAddress);
+ f->usb_transfer_mode = USB_BULK;
+ packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (ep_addr & 0x80)
+ f->pipe = usb_rcvisocpipe(dev,
+ ep->desc.bEndpointAddress);
+ else
+ f->pipe = usb_sndisocpipe(dev,
+ ep->desc.bEndpointAddress);
+ f->usb_transfer_mode = USB_ISOC;
+ iso_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
+ break;
+ default:
+ f->pipe = 0;
+ }
+
+ if (f->pipe) {
+ f->fifonum = idx & 7;
+ f->hw = hw;
+ f->usb_packet_maxlen =
+ le16_to_cpu(ep->desc.wMaxPacketSize);
+ f->intervall = ep->desc.bInterval;
+ }
+ ep++;
+ }
+ hw->dev = dev; /* save device */
+ hw->if_used = ifnum; /* save used interface */
+ hw->alt_used = alt_used; /* and alternate config */
+ hw->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */
+ hw->cfg_used = vcf[16]; /* store used config */
+ hw->vend_idx = vend_idx; /* store found vendor */
+ hw->packet_size = packet_size;
+ hw->iso_packet_size = iso_packet_size;
+
+ /* create the control pipes needed for register access */
+ hw->ctrl_in_pipe = usb_rcvctrlpipe(hw->dev, 0);
+ hw->ctrl_out_pipe = usb_sndctrlpipe(hw->dev, 0);
+ hw->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+ driver_info =
+ (struct hfcsusb_vdata *)hfcsusb_idtab[vend_idx].driver_info;
+ printk(KERN_DEBUG "%s: %s: detected \"%s\" (%s, if=%d alt=%d)\n",
+ hw->name, __func__, driver_info->vend_name,
+ conf_str[small_match], ifnum, alt_used);
+
+ if (setup_instance(hw, dev->dev.parent))
+ return -EIO;
+
+ hw->intf = intf;
+ usb_set_intfdata(hw->intf, hw);
+ return 0;
+}
+
+/* function called when an active device is removed */
+static void
+hfcsusb_disconnect(struct usb_interface *intf)
+{
+ struct hfcsusb *hw = usb_get_intfdata(intf);
+ struct hfcsusb *next;
+ int cnt = 0;
+
+ printk(KERN_INFO "%s: device disconnected\n", hw->name);
+
+ handle_led(hw, LED_POWER_OFF);
+ release_hw(hw);
+
+ list_for_each_entry_safe(hw, next, &HFClist, list)
+ cnt++;
+ if (!cnt)
+ hfcsusb_cnt = 0;
+
+ usb_set_intfdata(intf, NULL);
+}
+
+static struct usb_driver hfcsusb_drv = {
+ .name = DRIVER_NAME,
+ .id_table = hfcsusb_idtab,
+ .probe = hfcsusb_probe,
+ .disconnect = hfcsusb_disconnect,
+};
+
+static int __init
+hfcsusb_init(void)
+{
+ printk(KERN_INFO DRIVER_NAME " driver Rev. %s debug(0x%x) poll(%i)\n",
+ hfcsusb_rev, debug, poll);
+
+ if (usb_register(&hfcsusb_drv)) {
+ printk(KERN_INFO DRIVER_NAME
+ ": Unable to register hfcsusb module at usb stack\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit
+hfcsusb_cleanup(void)
+{
+ if (debug & DBG_HFC_CALL_TRACE)
+ printk(KERN_INFO DRIVER_NAME ": %s\n", __func__);
+
+ /* unregister Hardware */
+ usb_deregister(&hfcsusb_drv); /* release our driver */
+}
+
+module_init(hfcsusb_init);
+module_exit(hfcsusb_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.h b/drivers/isdn/hardware/mISDN/hfcsusb.h
new file mode 100644
index 000000000000..098486b8e8d2
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.h
@@ -0,0 +1,418 @@
+/*
+ * hfcsusb.h, HFC-S USB mISDN driver
+ */
+
+#ifndef __HFCSUSB_H__
+#define __HFCSUSB_H__
+
+
+#define DRIVER_NAME "HFC-S_USB"
+
+#define DBG_HFC_CALL_TRACE 0x00010000
+#define DBG_HFC_FIFO_VERBOSE 0x00020000
+#define DBG_HFC_USB_VERBOSE 0x00100000
+#define DBG_HFC_URB_INFO 0x00200000
+#define DBG_HFC_URB_ERROR 0x00400000
+
+#define DEFAULT_TRANSP_BURST_SZ 128
+
+#define HFC_CTRL_TIMEOUT 20 /* 5ms timeout writing/reading regs */
+#define CLKDEL_TE 0x0f /* CLKDEL in TE mode */
+#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */
+
+/* hfcsusb Layer1 commands */
+#define HFC_L1_ACTIVATE_TE 1
+#define HFC_L1_ACTIVATE_NT 2
+#define HFC_L1_DEACTIVATE_NT 3
+#define HFC_L1_FORCE_DEACTIVATE_TE 4
+
+/* cmd FLAGS in HFCUSB_STATES register */
+#define HFCUSB_LOAD_STATE 0x10
+#define HFCUSB_ACTIVATE 0x20
+#define HFCUSB_DO_ACTION 0x40
+#define HFCUSB_NT_G2_G3 0x80
+
+/* timers */
+#define NT_ACTIVATION_TIMER 0x01 /* enables NT mode activation Timer */
+#define NT_T1_COUNT 10
+
+#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */
+
+#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */
+#define HFCUSB_TX_THRESHOLD 96 /* threshold for fifo report bit tx */
+
+#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */
+#define HFCUSB_CIRM 0x00 /* cirm register index */
+#define HFCUSB_USB_SIZE 0x07 /* int length register */
+#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */
+#define HFCUSB_F_CROSS 0x0b /* bit order register */
+#define HFCUSB_CLKDEL 0x37 /* bit delay register */
+#define HFCUSB_CON_HDLC 0xfa /* channel connect register */
+#define HFCUSB_HDLC_PAR 0xfb
+#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */
+#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */
+#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */
+#define HFCUSB_F_THRES 0x0c /* threshold register */
+#define HFCUSB_FIFO 0x0f /* fifo select register */
+#define HFCUSB_F_USAGE 0x1a /* fifo usage register */
+#define HFCUSB_MST_MODE0 0x14
+#define HFCUSB_MST_MODE1 0x15
+#define HFCUSB_P_DATA 0x1f
+#define HFCUSB_INC_RES_F 0x0e
+#define HFCUSB_B1_SSL 0x20
+#define HFCUSB_B2_SSL 0x21
+#define HFCUSB_B1_RSL 0x24
+#define HFCUSB_B2_RSL 0x25
+#define HFCUSB_STATES 0x30
+
+
+#define HFCUSB_CHIPID 0x40 /* ID value of HFC-S USB */
+
+/* fifo registers */
+#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */
+#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */
+#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */
+#define HFCUSB_B2_TX 2
+#define HFCUSB_B2_RX 3
+#define HFCUSB_D_TX 4
+#define HFCUSB_D_RX 5
+#define HFCUSB_PCM_TX 6
+#define HFCUSB_PCM_RX 7
+
+
+#define USB_INT 0
+#define USB_BULK 1
+#define USB_ISOC 2
+
+#define ISOC_PACKETS_D 8
+#define ISOC_PACKETS_B 8
+#define ISO_BUFFER_SIZE 128
+
+/* defines how much ISO packets are handled in one URB */
+static int iso_packets[8] =
+ { ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B,
+ ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D
+};
+
+
+/* Fifo flow Control for TX ISO */
+#define SINK_MAX 68
+#define SINK_MIN 48
+#define SINK_DMIN 12
+#define SINK_DMAX 18
+#define BITLINE_INF (-96*8)
+
+/* HFC-S USB register access by Control-URSs */
+#define write_reg_atomic(a, b, c) \
+ usb_control_msg((a)->dev, (a)->ctrl_out_pipe, 0, 0x40, (c), (b), \
+ 0, 0, HFC_CTRL_TIMEOUT)
+#define read_reg_atomic(a, b, c) \
+ usb_control_msg((a)->dev, (a)->ctrl_in_pipe, 1, 0xC0, 0, (b), (c), \
+ 1, HFC_CTRL_TIMEOUT)
+#define HFC_CTRL_BUFSIZE 64
+
+struct ctrl_buf {
+ __u8 hfcs_reg; /* register number */
+ __u8 reg_val; /* value to be written (or read) */
+};
+
+/*
+ * URB error codes
+ * Used to represent a list of values and their respective symbolic names
+ */
+struct hfcusb_symbolic_list {
+ const int num;
+ const char *name;
+};
+
+static struct hfcusb_symbolic_list urb_errlist[] = {
+ {-ENOMEM, "No memory for allocation of internal structures"},
+ {-ENOSPC, "The host controller's bandwidth is already consumed"},
+ {-ENOENT, "URB was canceled by unlink_urb"},
+ {-EXDEV, "ISO transfer only partially completed"},
+ {-EAGAIN, "Too match scheduled for the future"},
+ {-ENXIO, "URB already queued"},
+ {-EFBIG, "Too much ISO frames requested"},
+ {-ENOSR, "Buffer error (overrun)"},
+ {-EPIPE, "Specified endpoint is stalled (device not responding)"},
+ {-EOVERFLOW, "Babble (bad cable?)"},
+ {-EPROTO, "Bit-stuff error (bad cable?)"},
+ {-EILSEQ, "CRC/Timeout"},
+ {-ETIMEDOUT, "NAK (device does not respond)"},
+ {-ESHUTDOWN, "Device unplugged"},
+ {-1, NULL}
+};
+
+static inline const char *
+symbolic(struct hfcusb_symbolic_list list[], const int num)
+{
+ int i;
+ for (i = 0; list[i].name != NULL; i++)
+ if (list[i].num == num)
+ return list[i].name;
+ return "<unkown USB Error>";
+}
+
+/* USB descriptor need to contain one of the following EndPoint combination: */
+#define CNF_4INT3ISO 1 /* 4 INT IN, 3 ISO OUT */
+#define CNF_3INT3ISO 2 /* 3 INT IN, 3 ISO OUT */
+#define CNF_4ISO3ISO 3 /* 4 ISO IN, 3 ISO OUT */
+#define CNF_3ISO3ISO 4 /* 3 ISO IN, 3 ISO OUT */
+
+#define EP_NUL 1 /* Endpoint at this position not allowed */
+#define EP_NOP 2 /* all type of endpoints allowed at this position */
+#define EP_ISO 3 /* Isochron endpoint mandatory at this position */
+#define EP_BLK 4 /* Bulk endpoint mandatory at this position */
+#define EP_INT 5 /* Interrupt endpoint mandatory at this position */
+
+#define HFC_CHAN_B1 0
+#define HFC_CHAN_B2 1
+#define HFC_CHAN_D 2
+#define HFC_CHAN_E 3
+
+
+/*
+ * List of all supported enpoints configiration sets, used to find the
+ * best matching endpoint configuration within a devices' USB descriptor.
+ * We need at least 3 RX endpoints, and 3 TX endpoints, either
+ * INT-in and ISO-out, or ISO-in and ISO-out)
+ * with 4 RX endpoints even E-Channel logging is possible
+ */
+static int
+validconf[][19] = {
+ /* INT in, ISO out config */
+ {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT,
+ EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
+ CNF_4INT3ISO, 2, 1},
+ {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_NUL,
+ EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
+ CNF_3INT3ISO, 2, 0},
+ /* ISO in, ISO out config */
+ {EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP,
+ EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NOP, EP_ISO,
+ CNF_4ISO3ISO, 2, 1},
+ {EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL,
+ EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NUL, EP_NUL,
+ CNF_3ISO3ISO, 2, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* EOL element */
+};
+
+/* string description of chosen config */
+char *conf_str[] = {
+ "4 Interrupt IN + 3 Isochron OUT",
+ "3 Interrupt IN + 3 Isochron OUT",
+ "4 Isochron IN + 3 Isochron OUT",
+ "3 Isochron IN + 3 Isochron OUT"
+};
+
+
+#define LED_OFF 0 /* no LED support */
+#define LED_SCHEME1 1 /* LED standard scheme */
+#define LED_SCHEME2 2 /* not used yet... */
+
+#define LED_POWER_ON 1
+#define LED_POWER_OFF 2
+#define LED_S0_ON 3
+#define LED_S0_OFF 4
+#define LED_B1_ON 5
+#define LED_B1_OFF 6
+#define LED_B1_DATA 7
+#define LED_B2_ON 8
+#define LED_B2_OFF 9
+#define LED_B2_DATA 10
+
+#define LED_NORMAL 0 /* LEDs are normal */
+#define LED_INVERTED 1 /* LEDs are inverted */
+
+/* time in ms to perform a Flashing LED when B-Channel has traffic */
+#define LED_TIME 250
+
+
+
+struct hfcsusb;
+struct usb_fifo;
+
+/* structure defining input+output fifos (interrupt/bulk mode) */
+struct iso_urb {
+ struct urb *urb;
+ __u8 buffer[ISO_BUFFER_SIZE]; /* buffer rx/tx USB URB data */
+ struct usb_fifo *owner_fifo; /* pointer to owner fifo */
+ __u8 indx; /* Fifos's ISO double buffer 0 or 1 ? */
+#ifdef ISO_FRAME_START_DEBUG
+ int start_frames[ISO_FRAME_START_RING_COUNT];
+ __u8 iso_frm_strt_pos; /* index in start_frame[] */
+#endif
+};
+
+struct usb_fifo {
+ int fifonum; /* fifo index attached to this structure */
+ int active; /* fifo is currently active */
+ struct hfcsusb *hw; /* pointer to main structure */
+ int pipe; /* address of endpoint */
+ __u8 usb_packet_maxlen; /* maximum length for usb transfer */
+ unsigned int max_size; /* maximum size of receive/send packet */
+ __u8 intervall; /* interrupt interval */
+ struct urb *urb; /* transfer structure for usb routines */
+ __u8 buffer[128]; /* buffer USB INT OUT URB data */
+ int bit_line; /* how much bits are in the fifo? */
+
+ __u8 usb_transfer_mode; /* switched between ISO and INT */
+ struct iso_urb iso[2]; /* two urbs to have one always
+ one pending */
+
+ struct dchannel *dch; /* link to hfcsusb_t->dch */
+ struct bchannel *bch; /* link to hfcsusb_t->bch */
+ struct dchannel *ech; /* link to hfcsusb_t->ech, TODO: E-CHANNEL */
+ int last_urblen; /* remember length of last packet */
+ __u8 stop_gracefull; /* stops URB retransmission */
+};
+
+struct hfcsusb {
+ struct list_head list;
+ struct dchannel dch;
+ struct bchannel bch[2];
+ struct dchannel ech; /* TODO : wait for struct echannel ;) */
+
+ struct usb_device *dev; /* our device */
+ struct usb_interface *intf; /* used interface */
+ int if_used; /* used interface number */
+ int alt_used; /* used alternate config */
+ int cfg_used; /* configuration index used */
+ int vend_idx; /* index in hfcsusb_idtab */
+ int packet_size;
+ int iso_packet_size;
+ struct usb_fifo fifos[HFCUSB_NUM_FIFOS];
+
+ /* control pipe background handling */
+ struct ctrl_buf ctrl_buff[HFC_CTRL_BUFSIZE];
+ int ctrl_in_idx, ctrl_out_idx, ctrl_cnt;
+ struct urb *ctrl_urb;
+ struct usb_ctrlrequest ctrl_write;
+ struct usb_ctrlrequest ctrl_read;
+ int ctrl_paksize;
+ int ctrl_in_pipe, ctrl_out_pipe;
+ spinlock_t ctrl_lock; /* lock for ctrl */
+ spinlock_t lock;
+
+ __u8 threshold_mask;
+ __u8 led_state;
+
+ __u8 protocol;
+ int nt_timer;
+ int open;
+ __u8 timers;
+ __u8 initdone;
+ char name[MISDN_MAX_IDLEN];
+};
+
+/* private vendor specific data */
+struct hfcsusb_vdata {
+ __u8 led_scheme; /* led display scheme */
+ signed short led_bits[8]; /* array of 8 possible LED bitmask */
+ char *vend_name; /* device name */
+};
+
+
+#define HFC_MAX_TE_LAYER1_STATE 8
+#define HFC_MAX_NT_LAYER1_STATE 4
+
+const char *HFC_TE_LAYER1_STATES[HFC_MAX_TE_LAYER1_STATE + 1] = {
+ "TE F0 - Reset",
+ "TE F1 - Reset",
+ "TE F2 - Sensing",
+ "TE F3 - Deactivated",
+ "TE F4 - Awaiting signal",
+ "TE F5 - Identifying input",
+ "TE F6 - Synchronized",
+ "TE F7 - Activated",
+ "TE F8 - Lost framing",
+};
+
+const char *HFC_NT_LAYER1_STATES[HFC_MAX_NT_LAYER1_STATE + 1] = {
+ "NT G0 - Reset",
+ "NT G1 - Deactive",
+ "NT G2 - Pending activation",
+ "NT G3 - Active",
+ "NT G4 - Pending deactivation",
+};
+
+/* supported devices */
+static struct usb_device_id hfcsusb_idtab[] = {
+ {
+ USB_DEVICE(0x0959, 0x2bd0),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_OFF, {4, 0, 2, 1},
+ "ISDN USB TA (Cologne Chip HFC-S USB based)"}),
+ },
+ {
+ USB_DEVICE(0x0675, 0x1688),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_SCHEME1, {1, 2, 0, 0},
+ "DrayTek miniVigor 128 USB ISDN TA"}),
+ },
+ {
+ USB_DEVICE(0x07b0, 0x0007),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_SCHEME1, {0x80, -64, -32, -16},
+ "Billion tiny USB ISDN TA 128"}),
+ },
+ {
+ USB_DEVICE(0x0742, 0x2008),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_SCHEME1, {4, 0, 2, 1},
+ "Stollmann USB TA"}),
+ },
+ {
+ USB_DEVICE(0x0742, 0x2009),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_SCHEME1, {4, 0, 2, 1},
+ "Aceex USB ISDN TA"}),
+ },
+ {
+ USB_DEVICE(0x0742, 0x200A),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_SCHEME1, {4, 0, 2, 1},
+ "OEM USB ISDN TA"}),
+ },
+ {
+ USB_DEVICE(0x08e3, 0x0301),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_SCHEME1, {2, 0, 1, 4},
+ "Olitec USB RNIS"}),
+ },
+ {
+ USB_DEVICE(0x07fa, 0x0846),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_SCHEME1, {0x80, -64, -32, -16},
+ "Bewan Modem RNIS USB"}),
+ },
+ {
+ USB_DEVICE(0x07fa, 0x0847),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_SCHEME1, {0x80, -64, -32, -16},
+ "Djinn Numeris USB"}),
+ },
+ {
+ USB_DEVICE(0x07b0, 0x0006),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_SCHEME1, {0x80, -64, -32, -16},
+ "Twister ISDN TA"}),
+ },
+ {
+ USB_DEVICE(0x071d, 0x1005),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_SCHEME1, {0x02, 0, 0x01, 0x04},
+ "Eicon DIVA USB 4.0"}),
+ },
+ {
+ USB_DEVICE(0x0586, 0x0102),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_SCHEME1, {0x88, -64, -32, -16},
+ "ZyXEL OMNI.NET USB II"}),
+ },
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, hfcsusb_idtab);
+
+#endif /* __HFCSUSB_H__ */
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c
index 7ee5bd9f2bb4..579974cf4c9a 100644
--- a/drivers/isdn/hysdn/hysdn_net.c
+++ b/drivers/isdn/hysdn/hysdn_net.c
@@ -38,16 +38,12 @@ char *hysdn_net_revision = "$Revision: 1.8.6.4 $";
/* inside the definition. */
/****************************************************************************/
struct net_local {
- struct net_device netdev; /* the network device */
- struct net_device_stats stats;
- /* additional vars may be added here */
- char dev_name[9]; /* our own device name */
-
/* Tx control lock. This protects the transmit buffer ring
* state along with the "tx full" state of the driver. This
* means all netif_queue flow control actions are protected
* by this lock as well.
*/
+ struct net_device *dev;
spinlock_t lock;
struct sk_buff *skbs[MAX_SKB_BUFFERS]; /* pointers to tx-skbs */
int in_idx, out_idx; /* indexes to buffer ring */
@@ -55,15 +51,6 @@ struct net_local {
}; /* net_local */
-/*****************************************************/
-/* Get the current statistics for this card. */
-/* This may be called with the card open or closed ! */
-/*****************************************************/
-static struct net_device_stats *
-net_get_stats(struct net_device *dev)
-{
- return (&((struct net_local *) dev)->stats);
-} /* net_device_stats */
/*********************************************************************/
/* Open/initialize the board. This is called (in the current kernel) */
@@ -182,8 +169,8 @@ hysdn_tx_netack(hysdn_card * card)
if (!lp->sk_count)
return; /* error condition */
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += lp->skbs[lp->out_idx]->len;
+ lp->dev->stats.tx_packets++;
+ lp->dev->stats.tx_bytes += lp->skbs[lp->out_idx]->len;
dev_kfree_skb(lp->skbs[lp->out_idx++]); /* free skb */
if (lp->out_idx >= MAX_SKB_BUFFERS)
@@ -200,29 +187,30 @@ void
hysdn_rx_netpkt(hysdn_card * card, unsigned char *buf, unsigned short len)
{
struct net_local *lp = card->netif;
+ struct net_device *dev = lp->dev;
struct sk_buff *skb;
if (!lp)
return; /* non existing device */
- lp->stats.rx_bytes += len;
+ dev->stats.rx_bytes += len;
skb = dev_alloc_skb(len);
if (skb == NULL) {
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
- lp->netdev.name);
- lp->stats.rx_dropped++;
+ dev->name);
+ dev->stats.rx_dropped++;
return;
}
/* copy the data */
memcpy(skb_put(skb, len), buf, len);
/* determine the used protocol */
- skb->protocol = eth_type_trans(skb, &lp->netdev);
+ skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- lp->stats.rx_packets++; /* adjust packet count */
+ dev->stats.rx_packets++; /* adjust packet count */
+ netif_rx(skb);
} /* hysdn_rx_netpkt */
/*****************************************************/
@@ -242,24 +230,15 @@ hysdn_tx_netget(hysdn_card * card)
return (lp->skbs[lp->out_idx]); /* next packet to send */
} /* hysdn_tx_netget */
+static const struct net_device_ops hysdn_netdev_ops = {
+ .ndo_open = net_open,
+ .ndo_stop = net_close,
+ .ndo_start_xmit = net_send_packet,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
-/*******************************************/
-/* init function called by register device */
-/*******************************************/
-static int
-net_init(struct net_device *dev)
-{
- /* setup the function table */
- dev->open = net_open;
- dev->stop = net_close;
- dev->hard_start_xmit = net_send_packet;
- dev->get_stats = net_get_stats;
-
- /* Fill in the fields of the device structure with ethernet values. */
- ether_setup(dev);
-
- return (0); /* success */
-} /* net_init */
/*****************************************************************************/
/* hysdn_net_create creates a new net device for the given card. If a device */
@@ -271,28 +250,34 @@ hysdn_net_create(hysdn_card * card)
{
struct net_device *dev;
int i;
+ struct net_local *lp;
+
if(!card) {
printk(KERN_WARNING "No card-pt in hysdn_net_create!\n");
return (-ENOMEM);
}
hysdn_net_release(card); /* release an existing net device */
- if ((dev = kzalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) {
+
+ dev = alloc_etherdev(sizeof(struct net_local));
+ if (!dev) {
printk(KERN_WARNING "HYSDN: unable to allocate mem\n");
return (-ENOMEM);
}
+ lp = netdev_priv(dev);
+ lp->dev = dev;
+
+ dev->netdev_ops = &hysdn_netdev_ops;
spin_lock_init(&((struct net_local *) dev)->lock);
/* initialise necessary or informing fields */
dev->base_addr = card->iobase; /* IO address */
dev->irq = card->irq; /* irq */
- dev->init = net_init; /* the init function of the device */
- if(dev->name) {
- strcpy(dev->name, ((struct net_local *) dev)->dev_name);
- }
+
+ dev->netdev_ops = &hysdn_netdev_ops;
if ((i = register_netdev(dev))) {
printk(KERN_WARNING "HYSDN: unable to create network device\n");
- kfree(dev);
+ free_netdev(dev);
return (i);
}
dev->ml_priv = card; /* remember pointer to own data structure */
@@ -316,7 +301,7 @@ hysdn_net_release(hysdn_card * card)
return (0); /* non existing */
card->netif = NULL; /* clear out pointer */
- dev->stop(dev); /* close the device */
+ net_close(dev);
flush_tx_buffers((struct net_local *) dev); /* empty buffers */
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 023ea11d2f9e..cb8943da4f12 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -292,7 +292,9 @@ isdn_net_unbind_channel(isdn_net_local * lp)
lp->dialstate = 0;
dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
- isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET);
+ if (lp->isdn_device != -1 && lp->isdn_channel != -1)
+ isdn_free_channel(lp->isdn_device, lp->isdn_channel,
+ ISDN_USAGE_NET);
lp->flags &= ~ISDN_NET_CONNECTED;
lp->isdn_device = -1;
lp->isdn_channel = -1;
@@ -1485,6 +1487,24 @@ isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return (rc);
}
+
+static int isdn_net_ioctl(struct net_device *dev,
+ struct ifreq *ifr, int cmd)
+{
+ isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev);
+
+ switch (lp->p_encap) {
+#ifdef CONFIG_ISDN_PPP
+ case ISDN_NET_ENCAP_SYNCPPP:
+ return isdn_ppp_dev_ioctl(dev, ifr, cmd);
+#endif
+ case ISDN_NET_ENCAP_CISCOHDLCK:
+ return isdn_ciscohdlck_dev_ioctl(dev, ifr, cmd);
+ default:
+ return -EINVAL;
+ }
+}
+
/* called via cisco_timer.function */
static void
isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
@@ -1998,23 +2018,6 @@ isdn_net_init(struct net_device *ndev)
ushort max_hlhdr_len = 0;
int drvidx;
- ether_setup(ndev);
- ndev->header_ops = NULL;
-
- /* Setup the generic properties */
- ndev->mtu = 1500;
- ndev->flags = IFF_NOARP|IFF_POINTOPOINT;
- ndev->type = ARPHRD_ETHER;
- ndev->addr_len = ETH_ALEN;
- ndev->validate_addr = NULL;
-
- /* for clients with MPPP maybe higher values better */
- ndev->tx_queue_len = 30;
-
- /* The ISDN-specific entries in the device structure. */
- ndev->open = &isdn_net_open;
- ndev->hard_start_xmit = &isdn_net_start_xmit;
-
/*
* up till binding we ask the protocol layer to reserve as much
* as we might need for HL layer
@@ -2026,9 +2029,6 @@ isdn_net_init(struct net_device *ndev)
max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen;
ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
- ndev->stop = &isdn_net_close;
- ndev->get_stats = &isdn_net_get_stats;
- ndev->do_ioctl = NULL;
return 0;
}
@@ -2508,6 +2508,18 @@ isdn_net_force_dial(char *name)
return (isdn_net_force_dial_lp(p->local));
}
+/* The ISDN-specific entries in the device structure. */
+static const struct net_device_ops isdn_netdev_ops = {
+ .ndo_init = isdn_net_init,
+ .ndo_open = isdn_net_open,
+ .ndo_stop = isdn_net_close,
+ .ndo_do_ioctl = isdn_net_ioctl,
+
+ .ndo_start_xmit = isdn_net_start_xmit,
+ .ndo_get_stats = isdn_net_get_stats,
+ .ndo_tx_timeout = isdn_net_tx_timeout,
+};
+
/*
* Helper for alloc_netdev()
*/
@@ -2515,7 +2527,16 @@ static void _isdn_setup(struct net_device *dev)
{
isdn_net_local *lp = netdev_priv(dev);
- dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+ ether_setup(dev);
+
+ /* Setup the generic properties */
+ dev->flags = IFF_NOARP|IFF_POINTOPOINT;
+ dev->header_ops = NULL;
+ dev->netdev_ops = &isdn_netdev_ops;
+
+ /* for clients with MPPP maybe higher values better */
+ dev->tx_queue_len = 30;
+
lp->p_encap = ISDN_NET_ENCAP_RAWIP;
lp->magic = ISDN_NET_MAGIC;
lp->last = lp;
@@ -2570,7 +2591,7 @@ isdn_net_new(char *name, struct net_device *master)
return NULL;
}
netdev->local = netdev_priv(netdev->dev);
- netdev->dev->init = isdn_net_init;
+
if (master) {
/* Device shall be a slave */
struct net_device *p = MASTER_TO_SLAVE(master);
@@ -2588,7 +2609,6 @@ isdn_net_new(char *name, struct net_device *master)
/*
* Watchdog timer (currently) for master only.
*/
- netdev->dev->tx_timeout = isdn_net_tx_timeout;
netdev->dev->watchdog_timeo = ISDN_NET_TX_TIMEOUT;
if (register_netdev(netdev->dev) != 0) {
printk(KERN_WARNING "isdn_net: Could not register net-device\n");
@@ -2704,7 +2724,6 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
#else
p->dev->type = ARPHRD_PPP; /* change ARP type */
p->dev->addr_len = 0;
- p->dev->do_ioctl = isdn_ppp_dev_ioctl;
#endif
break;
case ISDN_NET_ENCAP_X25IFACE:
@@ -2718,7 +2737,6 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
#endif
break;
case ISDN_NET_ENCAP_CISCOHDLCK:
- p->dev->do_ioctl = isdn_ciscohdlck_dev_ioctl;
break;
default:
if( cfg->p_encap >= 0 &&
diff --git a/drivers/isdn/mISDN/Makefile b/drivers/isdn/mISDN/Makefile
index 1cb5e633cf75..0a6bd2a9e730 100644
--- a/drivers/isdn/mISDN/Makefile
+++ b/drivers/isdn/mISDN/Makefile
@@ -8,6 +8,6 @@ obj-$(CONFIG_MISDN_L1OIP) += l1oip.o
# multi objects
-mISDN_core-objs := core.o fsm.o socket.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o
+mISDN_core-objs := core.o fsm.o socket.o clock.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_pipeline.o dsp_hwec.o
l1oip-objs := l1oip_core.o l1oip_codec.o
diff --git a/drivers/isdn/mISDN/clock.c b/drivers/isdn/mISDN/clock.c
new file mode 100644
index 000000000000..44d9c3d5d33d
--- /dev/null
+++ b/drivers/isdn/mISDN/clock.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2008 by Andreas Eversberg <andreas@eversberg.eu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This 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.
+ *
+ * Quick API description:
+ *
+ * A clock source registers using mISDN_register_clock:
+ * name = text string to name clock source
+ * priority = value to priorize clock sources (0 = default)
+ * ctl = callback function to enable/disable clock source
+ * priv = private pointer of clock source
+ * return = pointer to clock source structure;
+ *
+ * Note: Callback 'ctl' can be called before mISDN_register_clock returns!
+ * Also it can be called during mISDN_unregister_clock.
+ *
+ * A clock source calls mISDN_clock_update with given samples elapsed, if
+ * enabled. If function call is delayed, tv must be set with the timestamp
+ * of the actual event.
+ *
+ * A clock source unregisters using mISDN_unregister_clock.
+ *
+ * To get current clock, call mISDN_clock_get. The signed short value
+ * counts the number of samples since. Time since last clock event is added.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/spinlock.h>
+#include <linux/mISDNif.h>
+#include "core.h"
+
+static u_int *debug;
+static LIST_HEAD(iclock_list);
+DEFINE_RWLOCK(iclock_lock);
+u16 iclock_count; /* counter of last clock */
+struct timeval iclock_tv; /* time stamp of last clock */
+int iclock_tv_valid; /* already received one timestamp */
+struct mISDNclock *iclock_current;
+
+void
+mISDN_init_clock(u_int *dp)
+{
+ debug = dp;
+ do_gettimeofday(&iclock_tv);
+}
+
+static void
+select_iclock(void)
+{
+ struct mISDNclock *iclock, *bestclock = NULL, *lastclock = NULL;
+ int pri = -128;
+
+ list_for_each_entry(iclock, &iclock_list, list) {
+ if (iclock->pri > pri) {
+ pri = iclock->pri;
+ bestclock = iclock;
+ }
+ if (iclock_current == iclock)
+ lastclock = iclock;
+ }
+ if (lastclock && bestclock != lastclock) {
+ /* last used clock source still exists but changes, disable */
+ if (*debug & DEBUG_CLOCK)
+ printk(KERN_DEBUG "Old clock source '%s' disable.\n",
+ lastclock->name);
+ lastclock->ctl(lastclock->priv, 0);
+ }
+ if (bestclock && bestclock != iclock_current) {
+ /* new clock source selected, enable */
+ if (*debug & DEBUG_CLOCK)
+ printk(KERN_DEBUG "New clock source '%s' enable.\n",
+ bestclock->name);
+ bestclock->ctl(bestclock->priv, 1);
+ }
+ if (bestclock != iclock_current) {
+ /* no clock received yet */
+ iclock_tv_valid = 0;
+ }
+ iclock_current = bestclock;
+}
+
+struct mISDNclock
+*mISDN_register_clock(char *name, int pri, clockctl_func_t *ctl, void *priv)
+{
+ u_long flags;
+ struct mISDNclock *iclock;
+
+ if (*debug & (DEBUG_CORE | DEBUG_CLOCK))
+ printk(KERN_DEBUG "%s: %s %d\n", __func__, name, pri);
+ iclock = kzalloc(sizeof(struct mISDNclock), GFP_ATOMIC);
+ if (!iclock) {
+ printk(KERN_ERR "%s: No memory for clock entry.\n", __func__);
+ return NULL;
+ }
+ strncpy(iclock->name, name, sizeof(iclock->name)-1);
+ iclock->pri = pri;
+ iclock->priv = priv;
+ iclock->ctl = ctl;
+ write_lock_irqsave(&iclock_lock, flags);
+ list_add_tail(&iclock->list, &iclock_list);
+ select_iclock();
+ write_unlock_irqrestore(&iclock_lock, flags);
+ return iclock;
+}
+EXPORT_SYMBOL(mISDN_register_clock);
+
+void
+mISDN_unregister_clock(struct mISDNclock *iclock)
+{
+ u_long flags;
+
+ if (*debug & (DEBUG_CORE | DEBUG_CLOCK))
+ printk(KERN_DEBUG "%s: %s %d\n", __func__, iclock->name,
+ iclock->pri);
+ write_lock_irqsave(&iclock_lock, flags);
+ if (iclock_current == iclock) {
+ if (*debug & DEBUG_CLOCK)
+ printk(KERN_DEBUG
+ "Current clock source '%s' unregisters.\n",
+ iclock->name);
+ iclock->ctl(iclock->priv, 0);
+ }
+ list_del(&iclock->list);
+ select_iclock();
+ write_unlock_irqrestore(&iclock_lock, flags);
+}
+EXPORT_SYMBOL(mISDN_unregister_clock);
+
+void
+mISDN_clock_update(struct mISDNclock *iclock, int samples, struct timeval *tv)
+{
+ u_long flags;
+ struct timeval tv_now;
+ time_t elapsed_sec;
+ int elapsed_8000th;
+
+ write_lock_irqsave(&iclock_lock, flags);
+ if (iclock_current != iclock) {
+ printk(KERN_ERR "%s: '%s' sends us clock updates, but we do "
+ "listen to '%s'. This is a bug!\n", __func__,
+ iclock->name,
+ iclock_current ? iclock_current->name : "nothing");
+ iclock->ctl(iclock->priv, 0);
+ write_unlock_irqrestore(&iclock_lock, flags);
+ return;
+ }
+ if (iclock_tv_valid) {
+ /* increment sample counter by given samples */
+ iclock_count += samples;
+ if (tv) { /* tv must be set, if function call is delayed */
+ iclock_tv.tv_sec = tv->tv_sec;
+ iclock_tv.tv_usec = tv->tv_usec;
+ } else
+ do_gettimeofday(&iclock_tv);
+ } else {
+ /* calc elapsed time by system clock */
+ if (tv) { /* tv must be set, if function call is delayed */
+ tv_now.tv_sec = tv->tv_sec;
+ tv_now.tv_usec = tv->tv_usec;
+ } else
+ do_gettimeofday(&tv_now);
+ elapsed_sec = tv_now.tv_sec - iclock_tv.tv_sec;
+ elapsed_8000th = (tv_now.tv_usec / 125)
+ - (iclock_tv.tv_usec / 125);
+ if (elapsed_8000th < 0) {
+ elapsed_sec -= 1;
+ elapsed_8000th += 8000;
+ }
+ /* add elapsed time to counter and set new timestamp */
+ iclock_count += elapsed_sec * 8000 + elapsed_8000th;
+ iclock_tv.tv_sec = tv_now.tv_sec;
+ iclock_tv.tv_usec = tv_now.tv_usec;
+ iclock_tv_valid = 1;
+ if (*debug & DEBUG_CLOCK)
+ printk("Received first clock from source '%s'.\n",
+ iclock_current ? iclock_current->name : "nothing");
+ }
+ write_unlock_irqrestore(&iclock_lock, flags);
+}
+EXPORT_SYMBOL(mISDN_clock_update);
+
+unsigned short
+mISDN_clock_get(void)
+{
+ u_long flags;
+ struct timeval tv_now;
+ time_t elapsed_sec;
+ int elapsed_8000th;
+ u16 count;
+
+ read_lock_irqsave(&iclock_lock, flags);
+ /* calc elapsed time by system clock */
+ do_gettimeofday(&tv_now);
+ elapsed_sec = tv_now.tv_sec - iclock_tv.tv_sec;
+ elapsed_8000th = (tv_now.tv_usec / 125) - (iclock_tv.tv_usec / 125);
+ if (elapsed_8000th < 0) {
+ elapsed_sec -= 1;
+ elapsed_8000th += 8000;
+ }
+ /* add elapsed time to counter */
+ count = iclock_count + elapsed_sec * 8000 + elapsed_8000th;
+ read_unlock_irqrestore(&iclock_lock, flags);
+ return count;
+}
+EXPORT_SYMBOL(mISDN_clock_get);
+
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c
index 751665c448d0..9426c9827e47 100644
--- a/drivers/isdn/mISDN/core.c
+++ b/drivers/isdn/mISDN/core.c
@@ -25,39 +25,183 @@ MODULE_AUTHOR("Karsten Keil");
MODULE_LICENSE("GPL");
module_param(debug, uint, S_IRUGO | S_IWUSR);
-static LIST_HEAD(devices);
-static DEFINE_RWLOCK(device_lock);
static u64 device_ids;
#define MAX_DEVICE_ID 63
static LIST_HEAD(Bprotocols);
static DEFINE_RWLOCK(bp_lock);
+static void mISDN_dev_release(struct device *dev)
+{
+ /* nothing to do: the device is part of its parent's data structure */
+}
+
+static ssize_t _show_id(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mISDNdevice *mdev = dev_to_mISDN(dev);
+
+ if (!mdev)
+ return -ENODEV;
+ return sprintf(buf, "%d\n", mdev->id);
+}
+
+static ssize_t _show_nrbchan(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mISDNdevice *mdev = dev_to_mISDN(dev);
+
+ if (!mdev)
+ return -ENODEV;
+ return sprintf(buf, "%d\n", mdev->nrbchan);
+}
+
+static ssize_t _show_d_protocols(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mISDNdevice *mdev = dev_to_mISDN(dev);
+
+ if (!mdev)
+ return -ENODEV;
+ return sprintf(buf, "%d\n", mdev->Dprotocols);
+}
+
+static ssize_t _show_b_protocols(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mISDNdevice *mdev = dev_to_mISDN(dev);
+
+ if (!mdev)
+ return -ENODEV;
+ return sprintf(buf, "%d\n", mdev->Bprotocols | get_all_Bprotocols());
+}
+
+static ssize_t _show_protocol(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mISDNdevice *mdev = dev_to_mISDN(dev);
+
+ if (!mdev)
+ return -ENODEV;
+ return sprintf(buf, "%d\n", mdev->D.protocol);
+}
+
+static ssize_t _show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ strcpy(buf, dev_name(dev));
+ return strlen(buf);
+}
+
+#if 0 /* hangs */
+static ssize_t _set_name(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err = 0;
+ char *out = kmalloc(count + 1, GFP_KERNEL);
+
+ if (!out)
+ return -ENOMEM;
+
+ memcpy(out, buf, count);
+ if (count && out[count - 1] == '\n')
+ out[--count] = 0;
+ if (count)
+ err = device_rename(dev, out);
+ kfree(out);
+
+ return (err < 0) ? err : count;
+}
+#endif
+
+static ssize_t _show_channelmap(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct mISDNdevice *mdev = dev_to_mISDN(dev);
+ char *bp = buf;
+ int i;
+
+ for (i = 0; i <= mdev->nrbchan; i++)
+ *bp++ = test_channelmap(i, mdev->channelmap) ? '1' : '0';
+
+ return bp - buf;
+}
+
+static struct device_attribute mISDN_dev_attrs[] = {
+ __ATTR(id, S_IRUGO, _show_id, NULL),
+ __ATTR(d_protocols, S_IRUGO, _show_d_protocols, NULL),
+ __ATTR(b_protocols, S_IRUGO, _show_b_protocols, NULL),
+ __ATTR(protocol, S_IRUGO, _show_protocol, NULL),
+ __ATTR(channelmap, S_IRUGO, _show_channelmap, NULL),
+ __ATTR(nrbchan, S_IRUGO, _show_nrbchan, NULL),
+ __ATTR(name, S_IRUGO, _show_name, NULL),
+/* __ATTR(name, S_IRUGO|S_IWUSR, _show_name, _set_name), */
+ {}
+};
+
+#ifdef CONFIG_HOTPLUG
+static int mISDN_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct mISDNdevice *mdev = dev_to_mISDN(dev);
+
+ if (!mdev)
+ return 0;
+
+ if (add_uevent_var(env, "nchans=%d", mdev->nrbchan))
+ return -ENOMEM;
+
+ return 0;
+}
+#endif
+
+static void mISDN_class_release(struct class *cls)
+{
+ /* do nothing, it's static */
+}
+
+static struct class mISDN_class = {
+ .name = "mISDN",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_HOTPLUG
+ .dev_uevent = mISDN_uevent,
+#endif
+ .dev_attrs = mISDN_dev_attrs,
+ .dev_release = mISDN_dev_release,
+ .class_release = mISDN_class_release,
+};
+
+static int
+_get_mdevice(struct device *dev, void *id)
+{
+ struct mISDNdevice *mdev = dev_to_mISDN(dev);
+
+ if (!mdev)
+ return 0;
+ if (mdev->id != *(u_int *)id)
+ return 0;
+ return 1;
+}
+
struct mISDNdevice
*get_mdevice(u_int id)
{
- struct mISDNdevice *dev;
+ return dev_to_mISDN(class_find_device(&mISDN_class, NULL, &id,
+ _get_mdevice));
+}
- read_lock(&device_lock);
- list_for_each_entry(dev, &devices, D.list)
- if (dev->id == id) {
- read_unlock(&device_lock);
- return dev;
- }
- read_unlock(&device_lock);
- return NULL;
+static int
+_get_mdevice_count(struct device *dev, void *cnt)
+{
+ *(int *)cnt += 1;
+ return 0;
}
int
get_mdevice_count(void)
{
- struct mISDNdevice *dev;
- int cnt = 0;
+ int cnt = 0;
- read_lock(&device_lock);
- list_for_each_entry(dev, &devices, D.list)
- cnt++;
- read_unlock(&device_lock);
+ class_for_each_device(&mISDN_class, NULL, &cnt, _get_mdevice_count);
return cnt;
}
@@ -68,48 +212,66 @@ get_free_devid(void)
for (i = 0; i <= MAX_DEVICE_ID; i++)
if (!test_and_set_bit(i, (u_long *)&device_ids))
- return i;
- return -1;
+ break;
+ if (i > MAX_DEVICE_ID)
+ return -1;
+ return i;
}
int
-mISDN_register_device(struct mISDNdevice *dev, char *name)
+mISDN_register_device(struct mISDNdevice *dev,
+ struct device *parent, char *name)
{
- u_long flags;
int err;
dev->id = get_free_devid();
+ err = -EBUSY;
if (dev->id < 0)
- return -EBUSY;
+ goto error1;
+
+ device_initialize(&dev->dev);
if (name && name[0])
- strcpy(dev->name, name);
+ dev_set_name(&dev->dev, "%s", name);
else
- sprintf(dev->name, "mISDN%d", dev->id);
+ dev_set_name(&dev->dev, "mISDN%d", dev->id);
if (debug & DEBUG_CORE)
printk(KERN_DEBUG "mISDN_register %s %d\n",
- dev->name, dev->id);
+ dev_name(&dev->dev), dev->id);
err = create_stack(dev);
if (err)
- return err;
- write_lock_irqsave(&device_lock, flags);
- list_add_tail(&dev->D.list, &devices);
- write_unlock_irqrestore(&device_lock, flags);
+ goto error1;
+
+ dev->dev.class = &mISDN_class;
+ dev->dev.platform_data = dev;
+ dev->dev.parent = parent;
+ dev_set_drvdata(&dev->dev, dev);
+
+ err = device_add(&dev->dev);
+ if (err)
+ goto error3;
return 0;
+
+error3:
+ delete_stack(dev);
+ return err;
+error1:
+ return err;
+
}
EXPORT_SYMBOL(mISDN_register_device);
void
mISDN_unregister_device(struct mISDNdevice *dev) {
- u_long flags;
-
if (debug & DEBUG_CORE)
printk(KERN_DEBUG "mISDN_unregister %s %d\n",
- dev->name, dev->id);
- write_lock_irqsave(&device_lock, flags);
- list_del(&dev->D.list);
- write_unlock_irqrestore(&device_lock, flags);
+ dev_name(&dev->dev), dev->id);
+ /* sysfs_remove_link(&dev->dev.kobj, "device"); */
+ device_del(&dev->dev);
+ dev_set_drvdata(&dev->dev, NULL);
+
test_and_clear_bit(dev->id, (u_long *)&device_ids);
delete_stack(dev);
+ put_device(&dev->dev);
}
EXPORT_SYMBOL(mISDN_unregister_device);
@@ -199,43 +361,45 @@ mISDNInit(void)
printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n",
MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE);
+ mISDN_init_clock(&debug);
mISDN_initstack(&debug);
+ err = class_register(&mISDN_class);
+ if (err)
+ goto error1;
err = mISDN_inittimer(&debug);
if (err)
- goto error;
+ goto error2;
err = l1_init(&debug);
- if (err) {
- mISDN_timer_cleanup();
- goto error;
- }
+ if (err)
+ goto error3;
err = Isdnl2_Init(&debug);
- if (err) {
- mISDN_timer_cleanup();
- l1_cleanup();
- goto error;
- }
+ if (err)
+ goto error4;
err = misdn_sock_init(&debug);
- if (err) {
- mISDN_timer_cleanup();
- l1_cleanup();
- Isdnl2_cleanup();
- }
-error:
+ if (err)
+ goto error5;
+ return 0;
+
+error5:
+ Isdnl2_cleanup();
+error4:
+ l1_cleanup();
+error3:
+ mISDN_timer_cleanup();
+error2:
+ class_unregister(&mISDN_class);
+error1:
return err;
}
static void mISDN_cleanup(void)
{
misdn_sock_cleanup();
- mISDN_timer_cleanup();
- l1_cleanup();
Isdnl2_cleanup();
+ l1_cleanup();
+ mISDN_timer_cleanup();
+ class_unregister(&mISDN_class);
- if (!list_empty(&devices))
- printk(KERN_ERR "%s devices still registered\n", __func__);
-
- if (!list_empty(&Bprotocols))
- printk(KERN_ERR "%s Bprotocols still registered\n", __func__);
printk(KERN_DEBUG "mISDNcore unloaded\n");
}
diff --git a/drivers/isdn/mISDN/core.h b/drivers/isdn/mISDN/core.h
index 7da7233b4c1a..7ac2f81a812b 100644
--- a/drivers/isdn/mISDN/core.h
+++ b/drivers/isdn/mISDN/core.h
@@ -74,4 +74,6 @@ extern void l1_cleanup(void);
extern int Isdnl2_Init(u_int *);
extern void Isdnl2_cleanup(void);
+extern void mISDN_init_clock(u_int *);
+
#endif
diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h
index 6c3fed6b8d4f..98a33c58f091 100644
--- a/drivers/isdn/mISDN/dsp.h
+++ b/drivers/isdn/mISDN/dsp.h
@@ -15,6 +15,7 @@
#define DEBUG_DSP_TONE 0x0020
#define DEBUG_DSP_BLOWFISH 0x0040
#define DEBUG_DSP_DELAY 0x0100
+#define DEBUG_DSP_CLOCK 0x0200
#define DEBUG_DSP_DTMFCOEFF 0x8000 /* heavy output */
/* options may be:
@@ -198,6 +199,7 @@ struct dsp {
/* hardware stuff */
struct dsp_features features;
int features_rx_off; /* set if rx_off is featured */
+ int features_fill_empty; /* set if fill_empty is featured */
int pcm_slot_rx; /* current PCM slot (or -1) */
int pcm_bank_rx;
int pcm_slot_tx;
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c
index c884511e2d49..58c43e429f73 100644
--- a/drivers/isdn/mISDN/dsp_cmx.c
+++ b/drivers/isdn/mISDN/dsp_cmx.c
@@ -137,6 +137,7 @@
/* #define CMX_CONF_DEBUG */
/*#define CMX_DEBUG * massive read/write pointer output */
+/*#define CMX_DELAY_DEBUG * gives rx-buffer delay overview */
/*#define CMX_TX_DEBUG * massive read/write on tx-buffer with content */
static inline int
@@ -744,11 +745,11 @@ conf_software:
if (dsp->pcm_slot_rx >= 0 &&
dsp->pcm_slot_rx <
sizeof(freeslots))
- freeslots[dsp->pcm_slot_tx] = 0;
+ freeslots[dsp->pcm_slot_rx] = 0;
if (dsp->pcm_slot_tx >= 0 &&
dsp->pcm_slot_tx <
sizeof(freeslots))
- freeslots[dsp->pcm_slot_rx] = 0;
+ freeslots[dsp->pcm_slot_tx] = 0;
}
}
i = 0;
@@ -836,11 +837,11 @@ conf_software:
if (dsp->pcm_slot_rx >= 0 &&
dsp->pcm_slot_rx <
sizeof(freeslots))
- freeslots[dsp->pcm_slot_tx] = 0;
+ freeslots[dsp->pcm_slot_rx] = 0;
if (dsp->pcm_slot_tx >= 0 &&
dsp->pcm_slot_tx <
sizeof(freeslots))
- freeslots[dsp->pcm_slot_rx] = 0;
+ freeslots[dsp->pcm_slot_tx] = 0;
}
}
i1 = 0;
@@ -926,10 +927,6 @@ conf_software:
/* for more than two members.. */
- /* in case of hdlc, we change to software */
- if (dsp->hdlc)
- goto conf_software;
-
/* if all members already have the same conference */
if (all_conf)
return;
@@ -940,6 +937,9 @@ conf_software:
if (current_conf >= 0) {
join_members:
list_for_each_entry(member, &conf->mlist, list) {
+ /* in case of hdlc, change to software */
+ if (member->dsp->hdlc)
+ goto conf_software;
/* join to current conference */
if (member->dsp->hfc_conf == current_conf)
continue;
@@ -1135,6 +1135,25 @@ dsp_cmx_conf(struct dsp *dsp, u32 conf_id)
return 0;
}
+#ifdef CMX_DELAY_DEBUG
+int delaycount;
+static void
+showdelay(struct dsp *dsp, int samples, int delay)
+{
+ char bar[] = "--------------------------------------------------|";
+ int sdelay;
+
+ delaycount += samples;
+ if (delaycount < 8000)
+ return;
+ delaycount = 0;
+
+ sdelay = delay * 50 / (dsp_poll << 2);
+
+ printk(KERN_DEBUG "DELAY (%s) %3d >%s\n", dsp->name, delay,
+ sdelay > 50 ? "..." : bar + 50 - sdelay);
+}
+#endif
/*
* audio data is received from card
@@ -1168,11 +1187,18 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb)
dsp->rx_init = 0;
if (dsp->features.unordered) {
dsp->rx_R = (hh->id & CMX_BUFF_MASK);
- dsp->rx_W = (dsp->rx_R + dsp->cmx_delay)
- & CMX_BUFF_MASK;
+ if (dsp->cmx_delay)
+ dsp->rx_W = (dsp->rx_R + dsp->cmx_delay)
+ & CMX_BUFF_MASK;
+ else
+ dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1))
+ & CMX_BUFF_MASK;
} else {
dsp->rx_R = 0;
- dsp->rx_W = dsp->cmx_delay;
+ if (dsp->cmx_delay)
+ dsp->rx_W = dsp->cmx_delay;
+ else
+ dsp->rx_W = dsp_poll >> 1;
}
}
/* if frame contains time code, write directly */
@@ -1185,19 +1211,25 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb)
* we set our new read pointer, and write silence to buffer
*/
if (((dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) {
- if (dsp_debug & DEBUG_DSP_CMX)
+ if (dsp_debug & DEBUG_DSP_CLOCK)
printk(KERN_DEBUG
"cmx_receive(dsp=%lx): UNDERRUN (or overrun the "
"maximum delay), adjusting read pointer! "
"(inst %s)\n", (u_long)dsp, dsp->name);
- /* flush buffer */
+ /* flush rx buffer and set delay to dsp_poll / 2 */
if (dsp->features.unordered) {
dsp->rx_R = (hh->id & CMX_BUFF_MASK);
- dsp->rx_W = (dsp->rx_R + dsp->cmx_delay)
- & CMX_BUFF_MASK;
+ if (dsp->cmx_delay)
+ dsp->rx_W = (dsp->rx_R + dsp->cmx_delay)
+ & CMX_BUFF_MASK;
+ dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1))
+ & CMX_BUFF_MASK;
} else {
dsp->rx_R = 0;
- dsp->rx_W = dsp->cmx_delay;
+ if (dsp->cmx_delay)
+ dsp->rx_W = dsp->cmx_delay;
+ else
+ dsp->rx_W = dsp_poll >> 1;
}
memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff));
}
@@ -1205,7 +1237,7 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb)
if (dsp->cmx_delay)
if (((dsp->rx_W - dsp->rx_R) & CMX_BUFF_MASK) >=
(dsp->cmx_delay << 1)) {
- if (dsp_debug & DEBUG_DSP_CMX)
+ if (dsp_debug & DEBUG_DSP_CLOCK)
printk(KERN_DEBUG
"cmx_receive(dsp=%lx): OVERRUN (because "
"twice the delay is reached), adjusting "
@@ -1243,6 +1275,9 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb)
/* increase write-pointer */
dsp->rx_W = ((dsp->rx_W+len) & CMX_BUFF_MASK);
+#ifdef CMX_DELAY_DEBUG
+ showdelay(dsp, len, (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK);
+#endif
}
@@ -1360,8 +1395,12 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members)
t = (t+1) & CMX_BUFF_MASK;
r = (r+1) & CMX_BUFF_MASK;
}
- if (r != rr)
+ if (r != rr) {
+ if (dsp_debug & DEBUG_DSP_CLOCK)
+ printk(KERN_DEBUG "%s: RX empty\n",
+ __func__);
memset(d, dsp_silence, (rr-r)&CMX_BUFF_MASK);
+ }
/* -> if echo is enabled */
} else {
/*
@@ -1540,13 +1579,11 @@ send_packet:
schedule_work(&dsp->workq);
}
-static u32 samplecount;
+static u32 jittercount; /* counter for jitter check */
struct timer_list dsp_spl_tl;
u32 dsp_spl_jiffies; /* calculate the next time to fire */
-#ifdef UNUSED
-static u32 dsp_start_jiffies; /* jiffies at the time, the calculation begins */
-#endif /* UNUSED */
-static struct timeval dsp_start_tv; /* time at start of calculation */
+static u16 dsp_count; /* last sample count */
+static int dsp_count_valid ; /* if we have last sample count */
void
dsp_cmx_send(void *arg)
@@ -1560,38 +1597,32 @@ dsp_cmx_send(void *arg)
int r, rr;
int jittercheck = 0, delay, i;
u_long flags;
- struct timeval tv;
- u32 elapsed;
- s16 length;
+ u16 length, count;
/* lock */
spin_lock_irqsave(&dsp_lock, flags);
- if (!dsp_start_tv.tv_sec) {
- do_gettimeofday(&dsp_start_tv);
+ if (!dsp_count_valid) {
+ dsp_count = mISDN_clock_get();
length = dsp_poll;
+ dsp_count_valid = 1;
} else {
- do_gettimeofday(&tv);
- elapsed = ((tv.tv_sec - dsp_start_tv.tv_sec) * 8000)
- + ((s32)(tv.tv_usec / 125) - (dsp_start_tv.tv_usec / 125));
- dsp_start_tv.tv_sec = tv.tv_sec;
- dsp_start_tv.tv_usec = tv.tv_usec;
- length = elapsed;
+ count = mISDN_clock_get();
+ length = count - dsp_count;
+ dsp_count = count;
}
if (length > MAX_POLL + 100)
length = MAX_POLL + 100;
-/* printk(KERN_DEBUG "len=%d dsp_count=0x%x.%04x dsp_poll_diff=0x%x.%04x\n",
- length, dsp_count >> 16, dsp_count & 0xffff, dsp_poll_diff >> 16,
- dsp_poll_diff & 0xffff);
- */
+ /* printk(KERN_DEBUG "len=%d dsp_count=0x%x\n", length, dsp_count); */
/*
- * check if jitter needs to be checked
- * (this is about every second = 8192 samples)
+ * check if jitter needs to be checked (this is every second)
*/
- samplecount += length;
- if ((samplecount & 8191) < length)
+ jittercount += length;
+ if (jittercount >= 8000) {
+ jittercount -= 8000;
jittercheck = 1;
+ }
/* loop all members that do not require conference mixing */
list_for_each_entry(dsp, &dsp_ilist, list) {
@@ -1704,17 +1735,19 @@ dsp_cmx_send(void *arg)
}
/*
* remove rx_delay only if we have delay AND we
- * have not preset cmx_delay
+ * have not preset cmx_delay AND
+ * the delay is greater dsp_poll
*/
- if (delay && !dsp->cmx_delay) {
- if (dsp_debug & DEBUG_DSP_CMX)
+ if (delay > dsp_poll && !dsp->cmx_delay) {
+ if (dsp_debug & DEBUG_DSP_CLOCK)
printk(KERN_DEBUG
"%s lowest rx_delay of %d bytes for"
" dsp %s are now removed.\n",
__func__, delay,
dsp->name);
r = dsp->rx_R;
- rr = (r + delay) & CMX_BUFF_MASK;
+ rr = (r + delay - (dsp_poll >> 1))
+ & CMX_BUFF_MASK;
/* delete rx-data */
while (r != rr) {
p[r] = dsp_silence;
@@ -1736,15 +1769,16 @@ dsp_cmx_send(void *arg)
* remove delay only if we have delay AND we
* have enabled tx_dejitter
*/
- if (delay && dsp->tx_dejitter) {
- if (dsp_debug & DEBUG_DSP_CMX)
+ if (delay > dsp_poll && dsp->tx_dejitter) {
+ if (dsp_debug & DEBUG_DSP_CLOCK)
printk(KERN_DEBUG
"%s lowest tx_delay of %d bytes for"
" dsp %s are now removed.\n",
__func__, delay,
dsp->name);
r = dsp->tx_R;
- rr = (r + delay) & CMX_BUFF_MASK;
+ rr = (r + delay - (dsp_poll >> 1))
+ & CMX_BUFF_MASK;
/* delete tx-data */
while (r != rr) {
q[r] = dsp_silence;
@@ -1797,14 +1831,16 @@ dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb)
ww = dsp->tx_R;
p = dsp->tx_buff;
d = skb->data;
- space = ww-w;
- if (space <= 0)
- space += CMX_BUFF_SIZE;
+ space = (ww - w - 1) & CMX_BUFF_MASK;
/* write-pointer should not overrun nor reach read pointer */
- if (space-1 < skb->len)
+ if (space < skb->len) {
/* write to the space we have left */
- ww = (ww - 1) & CMX_BUFF_MASK;
- else
+ ww = (ww - 1) & CMX_BUFF_MASK; /* end one byte prior tx_R */
+ if (dsp_debug & DEBUG_DSP_CLOCK)
+ printk(KERN_DEBUG "%s: TX overflow space=%d skb->len="
+ "%d, w=0x%04x, ww=0x%04x\n", __func__, space,
+ skb->len, w, ww);
+ } else
/* write until all byte are copied */
ww = (w + skb->len) & CMX_BUFF_MASK;
dsp->tx_W = ww;
@@ -1857,7 +1893,7 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb)
/* in case of hardware (echo) */
if (dsp->pcm_slot_tx >= 0)
return;
- if (dsp->echo)
+ if (dsp->echo) {
nskb = skb_clone(skb, GFP_ATOMIC);
if (nskb) {
hh = mISDN_HEAD_P(nskb);
@@ -1866,6 +1902,7 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb)
skb_queue_tail(&dsp->sendq, nskb);
schedule_work(&dsp->workq);
}
+ }
return;
}
/* in case of hardware conference */
diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c
index 1dc21d803410..3083338716b2 100644
--- a/drivers/isdn/mISDN/dsp_core.c
+++ b/drivers/isdn/mISDN/dsp_core.c
@@ -191,6 +191,8 @@ dsp_rx_off_member(struct dsp *dsp)
struct mISDN_ctrl_req cq;
int rx_off = 1;
+ memset(&cq, 0, sizeof(cq));
+
if (!dsp->features_rx_off)
return;
@@ -249,6 +251,32 @@ dsp_rx_off(struct dsp *dsp)
}
}
+/* enable "fill empty" feature */
+static void
+dsp_fill_empty(struct dsp *dsp)
+{
+ struct mISDN_ctrl_req cq;
+
+ memset(&cq, 0, sizeof(cq));
+
+ if (!dsp->ch.peer) {
+ if (dsp_debug & DEBUG_DSP_CORE)
+ printk(KERN_DEBUG "%s: no peer, no fill_empty\n",
+ __func__);
+ return;
+ }
+ cq.op = MISDN_CTRL_FILL_EMPTY;
+ cq.p1 = 1;
+ if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) {
+ printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n",
+ __func__);
+ return;
+ }
+ if (dsp_debug & DEBUG_DSP_CORE)
+ printk(KERN_DEBUG "%s: %s set fill_empty = 1\n",
+ __func__, dsp->name);
+}
+
static int
dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb)
{
@@ -273,8 +301,9 @@ dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb)
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: start dtmf\n", __func__);
if (len == sizeof(int)) {
- printk(KERN_NOTICE "changing DTMF Threshold "
- "to %d\n", *((int *)data));
+ if (dsp_debug & DEBUG_DSP_CORE)
+ printk(KERN_NOTICE "changing DTMF Threshold "
+ "to %d\n", *((int *)data));
dsp->dtmf.treshold = (*(int *)data) * 10000;
}
/* init goertzel */
@@ -593,8 +622,6 @@ get_features(struct mISDNchannel *ch)
struct dsp *dsp = container_of(ch, struct dsp, ch);
struct mISDN_ctrl_req cq;
- if (dsp_options & DSP_OPT_NOHARDWARE)
- return;
if (!ch->peer) {
if (dsp_debug & DEBUG_DSP_CORE)
printk(KERN_DEBUG "%s: no peer, no features\n",
@@ -610,6 +637,10 @@ get_features(struct mISDNchannel *ch)
}
if (cq.op & MISDN_CTRL_RX_OFF)
dsp->features_rx_off = 1;
+ if (cq.op & MISDN_CTRL_FILL_EMPTY)
+ dsp->features_fill_empty = 1;
+ if (dsp_options & DSP_OPT_NOHARDWARE)
+ return;
if ((cq.op & MISDN_CTRL_HW_FEATURES_OP)) {
cq.op = MISDN_CTRL_HW_FEATURES;
*((u_long *)&cq.p1) = (u_long)&dsp->features;
@@ -837,11 +868,14 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb)
}
if (dsp->hdlc) {
/* hdlc */
- spin_lock_irqsave(&dsp_lock, flags);
- if (dsp->b_active) {
- skb_queue_tail(&dsp->sendq, skb);
- schedule_work(&dsp->workq);
+ if (!dsp->b_active) {
+ ret = -EIO;
+ break;
}
+ hh->prim = PH_DATA_REQ;
+ spin_lock_irqsave(&dsp_lock, flags);
+ skb_queue_tail(&dsp->sendq, skb);
+ schedule_work(&dsp->workq);
spin_unlock_irqrestore(&dsp_lock, flags);
return 0;
}
@@ -865,6 +899,9 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb)
if (dsp->dtmf.hardware || dsp->dtmf.software)
dsp_dtmf_goertzel_init(dsp);
get_features(ch);
+ /* enable fill_empty feature */
+ if (dsp->features_fill_empty)
+ dsp_fill_empty(dsp);
/* send ph_activate */
hh->prim = PH_ACTIVATE_REQ;
if (ch->peer)
@@ -1105,7 +1142,7 @@ static int dsp_init(void)
} else {
poll = 8;
while (poll <= MAX_POLL) {
- tics = poll * HZ / 8000;
+ tics = (poll * HZ) / 8000;
if (tics * 8000 == poll * HZ) {
dsp_tics = tics;
dsp_poll = poll;
diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c
index 83639be7f7ad..18cf87c113e7 100644
--- a/drivers/isdn/mISDN/dsp_pipeline.c
+++ b/drivers/isdn/mISDN/dsp_pipeline.c
@@ -75,6 +75,15 @@ static struct device_attribute element_attributes[] = {
__ATTR(args, 0444, attr_show_args, NULL),
};
+static void
+mISDN_dsp_dev_release(struct device *dev)
+{
+ struct dsp_element_entry *entry =
+ container_of(dev, struct dsp_element_entry, dev);
+ list_del(&entry->list);
+ kfree(entry);
+}
+
int mISDN_dsp_element_register(struct mISDN_dsp_element *elem)
{
struct dsp_element_entry *entry;
@@ -83,13 +92,14 @@ int mISDN_dsp_element_register(struct mISDN_dsp_element *elem)
if (!elem)
return -EINVAL;
- entry = kzalloc(sizeof(struct dsp_element_entry), GFP_KERNEL);
+ entry = kzalloc(sizeof(struct dsp_element_entry), GFP_ATOMIC);
if (!entry)
return -ENOMEM;
entry->elem = elem;
entry->dev.class = elements_class;
+ entry->dev.release = mISDN_dsp_dev_release;
dev_set_drvdata(&entry->dev, elem);
dev_set_name(&entry->dev, elem->name);
ret = device_register(&entry->dev);
@@ -98,9 +108,9 @@ int mISDN_dsp_element_register(struct mISDN_dsp_element *elem)
__func__, elem->name);
goto err1;
}
+ list_add_tail(&entry->list, &dsp_elements);
- for (i = 0; i < (sizeof(element_attributes)
- / sizeof(struct device_attribute)); ++i)
+ for (i = 0; i < ARRAY_SIZE(element_attributes); ++i) {
ret = device_create_file(&entry->dev,
&element_attributes[i]);
if (ret) {
@@ -108,15 +118,17 @@ int mISDN_dsp_element_register(struct mISDN_dsp_element *elem)
__func__);
goto err2;
}
+ }
- list_add_tail(&entry->list, &dsp_elements);
-
+#ifdef PIPELINE_DEBUG
printk(KERN_DEBUG "%s: %s registered\n", __func__, elem->name);
+#endif
return 0;
err2:
device_unregister(&entry->dev);
+ return ret;
err1:
kfree(entry);
return ret;
@@ -132,11 +144,11 @@ void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem)
list_for_each_entry_safe(entry, n, &dsp_elements, list)
if (entry->elem == elem) {
- list_del(&entry->list);
device_unregister(&entry->dev);
- kfree(entry);
+#ifdef PIPELINE_DEBUG
printk(KERN_DEBUG "%s: %s unregistered\n",
__func__, elem->name);
+#endif
return;
}
printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name);
@@ -173,7 +185,9 @@ void dsp_pipeline_module_exit(void)
kfree(entry);
}
+#ifdef PIPELINE_DEBUG
printk(KERN_DEBUG "%s: dsp pipeline module exited\n", __func__);
+#endif
}
int dsp_pipeline_init(struct dsp_pipeline *pipeline)
@@ -239,7 +253,7 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
if (!len)
return 0;
- dup = kmalloc(len + 1, GFP_KERNEL);
+ dup = kmalloc(len + 1, GFP_ATOMIC);
if (!dup)
return 0;
strcpy(dup, cfg);
@@ -256,9 +270,9 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
elem = entry->elem;
pipeline_entry = kmalloc(sizeof(struct
- dsp_pipeline_entry), GFP_KERNEL);
+ dsp_pipeline_entry), GFP_ATOMIC);
if (!pipeline_entry) {
- printk(KERN_DEBUG "%s: failed to add "
+ printk(KERN_ERR "%s: failed to add "
"entry to pipeline: %s (out of "
"memory)\n", __func__, elem->name);
incomplete = 1;
@@ -286,7 +300,7 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
args : "");
#endif
} else {
- printk(KERN_DEBUG "%s: failed "
+ printk(KERN_ERR "%s: failed "
"to add entry to pipeline: "
"%s (new() returned NULL)\n",
__func__, elem->name);
@@ -301,7 +315,7 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
if (found)
found = 0;
else {
- printk(KERN_DEBUG "%s: element not found, skipping: "
+ printk(KERN_ERR "%s: element not found, skipping: "
"%s\n", __func__, name);
incomplete = 1;
}
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index 2596fba4e614..ab1168a110ae 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -50,9 +50,6 @@ bchannel_bh(struct work_struct *ws)
if (test_and_clear_bit(FLG_RECVQUEUE, &bch->Flags)) {
while ((skb = skb_dequeue(&bch->rqueue))) {
- if (bch->rcount >= 64)
- printk(KERN_WARNING "B-channel %p receive "
- "queue if full, but empties...\n", bch);
bch->rcount--;
if (likely(bch->ch.peer)) {
err = bch->ch.recv(bch->ch.peer, skb);
@@ -169,6 +166,25 @@ recv_Dchannel(struct dchannel *dch)
EXPORT_SYMBOL(recv_Dchannel);
void
+recv_Echannel(struct dchannel *ech, struct dchannel *dch)
+{
+ struct mISDNhead *hh;
+
+ if (ech->rx_skb->len < 2) { /* at least 2 for sapi / tei */
+ dev_kfree_skb(ech->rx_skb);
+ ech->rx_skb = NULL;
+ return;
+ }
+ hh = mISDN_HEAD_P(ech->rx_skb);
+ hh->prim = PH_DATA_E_IND;
+ hh->id = get_sapi_tei(ech->rx_skb->data);
+ skb_queue_tail(&dch->rqueue, ech->rx_skb);
+ ech->rx_skb = NULL;
+ schedule_event(dch, FLG_RECVQUEUE);
+}
+EXPORT_SYMBOL(recv_Echannel);
+
+void
recv_Bchannel(struct bchannel *bch)
{
struct mISDNhead *hh;
@@ -177,8 +193,10 @@ recv_Bchannel(struct bchannel *bch)
hh->prim = PH_DATA_IND;
hh->id = MISDN_ID_ANY;
if (bch->rcount >= 64) {
- dev_kfree_skb(bch->rx_skb);
- bch->rx_skb = NULL;
+ printk(KERN_WARNING "B-channel %p receive queue overflow, "
+ "fushing!\n", bch);
+ skb_queue_purge(&bch->rqueue);
+ bch->rcount = 0;
return;
}
bch->rcount++;
@@ -200,8 +218,10 @@ void
recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb)
{
if (bch->rcount >= 64) {
- dev_kfree_skb(skb);
- return;
+ printk(KERN_WARNING "B-channel %p receive queue overflow, "
+ "fushing!\n", bch);
+ skb_queue_purge(&bch->rqueue);
+ bch->rcount = 0;
}
bch->rcount++;
skb_queue_tail(&bch->rqueue, skb);
@@ -245,8 +265,12 @@ confirm_Bsend(struct bchannel *bch)
{
struct sk_buff *skb;
- if (bch->rcount >= 64)
- return;
+ if (bch->rcount >= 64) {
+ printk(KERN_WARNING "B-channel %p receive queue overflow, "
+ "fushing!\n", bch);
+ skb_queue_purge(&bch->rqueue);
+ bch->rcount = 0;
+ }
skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb),
0, NULL, GFP_ATOMIC);
if (!skb) {
diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c
index 0884dd6892f8..abe574989572 100644
--- a/drivers/isdn/mISDN/l1oip_core.c
+++ b/drivers/isdn/mISDN/l1oip_core.c
@@ -777,6 +777,8 @@ fail:
static void
l1oip_socket_close(struct l1oip *hc)
{
+ struct dchannel *dch = hc->chan[hc->d_idx].dch;
+
/* kill thread */
if (hc->socket_thread) {
if (debug & DEBUG_L1OIP_SOCKET)
@@ -785,6 +787,16 @@ l1oip_socket_close(struct l1oip *hc)
send_sig(SIGTERM, hc->socket_thread, 0);
wait_for_completion(&hc->socket_complete);
}
+
+ /* if active, we send up a PH_DEACTIVATE and deactivate */
+ if (test_bit(FLG_ACTIVE, &dch->Flags)) {
+ if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET))
+ printk(KERN_DEBUG "%s: interface become deactivated "
+ "due to timeout\n", __func__);
+ test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+ _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_ATOMIC);
+ }
}
static int
@@ -944,7 +956,8 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq)
switch (cq->op) {
case MISDN_CTRL_GETOP:
- cq->op = MISDN_CTRL_SETPEER | MISDN_CTRL_UNSETPEER;
+ cq->op = MISDN_CTRL_SETPEER | MISDN_CTRL_UNSETPEER
+ | MISDN_CTRL_GETPEER;
break;
case MISDN_CTRL_SETPEER:
hc->remoteip = (u32)cq->p1;
@@ -964,6 +977,13 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq)
hc->remoteip = 0;
l1oip_socket_open(hc);
break;
+ case MISDN_CTRL_GETPEER:
+ if (debug & DEBUG_L1OIP_SOCKET)
+ printk(KERN_DEBUG "%s: getting ip address.\n",
+ __func__);
+ cq->p1 = hc->remoteip;
+ cq->p2 = hc->remoteport | (hc->localport << 16);
+ break;
default:
printk(KERN_WARNING "%s: unknown Op %x\n",
__func__, cq->op);
@@ -1413,7 +1433,8 @@ init_card(struct l1oip *hc, int pri, int bundle)
hc->chan[i + ch].bch = bch;
set_channelmap(bch->nr, dch->dev.channelmap);
}
- ret = mISDN_register_device(&dch->dev, hc->name);
+ /* TODO: create a parent device for this driver */
+ ret = mISDN_register_device(&dch->dev, NULL, hc->name);
if (ret)
return ret;
hc->registered = 1;
diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c
index b73e952d12cf..e826eeb1ecec 100644
--- a/drivers/isdn/mISDN/layer1.c
+++ b/drivers/isdn/mISDN/layer1.c
@@ -101,7 +101,7 @@ l1m_debug(struct FsmInst *fi, char *fmt, ...)
va_list va;
va_start(va, fmt);
- printk(KERN_DEBUG "%s: ", l1->dch->dev.name);
+ printk(KERN_DEBUG "%s: ", dev_name(&l1->dch->dev.dev));
vprintk(fmt, va);
printk("\n");
va_end(va);
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index 37a2de18cfd0..508945d1b9c1 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -381,7 +381,7 @@ data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
memcpy(di.channelmap, dev->channelmap,
sizeof(di.channelmap));
di.nrbchan = dev->nrbchan;
- strcpy(di.name, dev->name);
+ strcpy(di.name, dev_name(&dev->dev));
if (copy_to_user((void __user *)arg, &di, sizeof(di)))
err = -EFAULT;
} else
@@ -460,6 +460,8 @@ data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
{
struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr;
struct sock *sk = sock->sk;
+ struct hlist_node *node;
+ struct sock *csk;
int err = 0;
if (*debug & DEBUG_SOCKET)
@@ -480,6 +482,26 @@ data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
err = -ENODEV;
goto done;
}
+
+ if (sk->sk_protocol < ISDN_P_B_START) {
+ read_lock_bh(&data_sockets.lock);
+ sk_for_each(csk, node, &data_sockets.head) {
+ if (sk == csk)
+ continue;
+ if (_pms(csk)->dev != _pms(sk)->dev)
+ continue;
+ if (csk->sk_protocol >= ISDN_P_B_START)
+ continue;
+ if (IS_ISDN_P_TE(csk->sk_protocol)
+ == IS_ISDN_P_TE(sk->sk_protocol))
+ continue;
+ read_unlock_bh(&data_sockets.lock);
+ err = -EBUSY;
+ goto done;
+ }
+ read_unlock_bh(&data_sockets.lock);
+ }
+
_pms(sk)->ch.send = mISDN_send;
_pms(sk)->ch.ctrl = mISDN_ctrl;
@@ -639,12 +661,27 @@ base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
memcpy(di.channelmap, dev->channelmap,
sizeof(di.channelmap));
di.nrbchan = dev->nrbchan;
- strcpy(di.name, dev->name);
+ strcpy(di.name, dev_name(&dev->dev));
if (copy_to_user((void __user *)arg, &di, sizeof(di)))
err = -EFAULT;
} else
err = -ENODEV;
break;
+ case IMSETDEVNAME:
+ {
+ struct mISDN_devrename dn;
+ if (copy_from_user(&dn, (void __user *)arg,
+ sizeof(dn))) {
+ err = -EFAULT;
+ break;
+ }
+ dev = get_mdevice(dn.id);
+ if (dev)
+ err = device_rename(&dev->dev, dn.name);
+ else
+ err = -ENODEV;
+ }
+ break;
default:
err = -EINVAL;
}
diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c
index d55b14ae4e99..e2f45019ebf0 100644
--- a/drivers/isdn/mISDN/stack.c
+++ b/drivers/isdn/mISDN/stack.c
@@ -172,7 +172,8 @@ send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb)
else
printk(KERN_WARNING
"%s: dev(%s) prim(%x) id(%x) no channel\n",
- __func__, st->dev->name, hh->prim, hh->id);
+ __func__, dev_name(&st->dev->dev), hh->prim,
+ hh->id);
} else if (lm == 0x8) {
WARN_ON(lm == 0x8);
ch = get_channel4id(st, hh->id);
@@ -181,11 +182,12 @@ send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb)
else
printk(KERN_WARNING
"%s: dev(%s) prim(%x) id(%x) no channel\n",
- __func__, st->dev->name, hh->prim, hh->id);
+ __func__, dev_name(&st->dev->dev), hh->prim,
+ hh->id);
} else {
/* broadcast not handled yet */
printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n",
- __func__, st->dev->name, hh->prim);
+ __func__, dev_name(&st->dev->dev), hh->prim);
}
return -ESRCH;
}
@@ -209,7 +211,8 @@ mISDNStackd(void *data)
unlock_kernel();
#endif
if (*debug & DEBUG_MSG_THREAD)
- printk(KERN_DEBUG "mISDNStackd %s started\n", st->dev->name);
+ printk(KERN_DEBUG "mISDNStackd %s started\n",
+ dev_name(&st->dev->dev));
if (st->notify != NULL) {
complete(st->notify);
@@ -245,7 +248,7 @@ mISDNStackd(void *data)
printk(KERN_DEBUG
"%s: %s prim(%x) id(%x) "
"send call(%d)\n",
- __func__, st->dev->name,
+ __func__, dev_name(&st->dev->dev),
mISDN_HEAD_PRIM(skb),
mISDN_HEAD_ID(skb), err);
dev_kfree_skb(skb);
@@ -288,7 +291,7 @@ mISDNStackd(void *data)
mISDN_STACK_ACTION_MASK));
if (*debug & DEBUG_MSG_THREAD)
printk(KERN_DEBUG "%s: %s wake status %08lx\n",
- __func__, st->dev->name, st->status);
+ __func__, dev_name(&st->dev->dev), st->status);
test_and_set_bit(mISDN_STACK_ACTIVE, &st->status);
test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status);
@@ -303,15 +306,16 @@ mISDNStackd(void *data)
#ifdef MISDN_MSG_STATS
printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d "
"msg %d sleep %d stopped\n",
- st->dev->name, st->msg_cnt, st->sleep_cnt, st->stopped_cnt);
+ dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt,
+ st->stopped_cnt);
printk(KERN_DEBUG
"mISDNStackd daemon for %s utime(%ld) stime(%ld)\n",
- st->dev->name, st->thread->utime, st->thread->stime);
+ dev_name(&st->dev->dev), st->thread->utime, st->thread->stime);
printk(KERN_DEBUG
"mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n",
- st->dev->name, st->thread->nvcsw, st->thread->nivcsw);
+ dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw);
printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n",
- st->dev->name);
+ dev_name(&st->dev->dev));
#endif
test_and_set_bit(mISDN_STACK_KILLED, &st->status);
test_and_clear_bit(mISDN_STACK_RUNNING, &st->status);
@@ -401,15 +405,16 @@ create_stack(struct mISDNdevice *dev)
newst->own.send = mISDN_queue_message;
newst->own.recv = mISDN_queue_message;
if (*debug & DEBUG_CORE_FUNC)
- printk(KERN_DEBUG "%s: st(%s)\n", __func__, newst->dev->name);
+ printk(KERN_DEBUG "%s: st(%s)\n", __func__,
+ dev_name(&newst->dev->dev));
newst->notify = &done;
newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s",
- newst->dev->name);
+ dev_name(&newst->dev->dev));
if (IS_ERR(newst->thread)) {
err = PTR_ERR(newst->thread);
printk(KERN_ERR
"mISDN:cannot create kernel thread for %s (%d)\n",
- newst->dev->name, err);
+ dev_name(&newst->dev->dev), err);
delete_teimanager(dev->teimgr);
kfree(newst);
} else
@@ -428,29 +433,21 @@ connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch,
if (*debug & DEBUG_CORE_FUNC)
printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
- __func__, dev->name, protocol, adr->dev, adr->channel,
- adr->sapi, adr->tei);
+ __func__, dev_name(&dev->dev), protocol, adr->dev,
+ adr->channel, adr->sapi, adr->tei);
switch (protocol) {
case ISDN_P_NT_S0:
case ISDN_P_NT_E1:
case ISDN_P_TE_S0:
case ISDN_P_TE_E1:
-#ifdef PROTOCOL_CHECK
- /* this should be enhanced */
- if (!list_empty(&dev->D.st->layer2)
- && dev->D.protocol != protocol)
- return -EBUSY;
- if (!hlist_empty(&dev->D.st->l1sock.head)
- && dev->D.protocol != protocol)
- return -EBUSY;
-#endif
ch->recv = mISDN_queue_message;
ch->peer = &dev->D.st->own;
ch->st = dev->D.st;
rq.protocol = protocol;
- rq.adr.channel = 0;
+ rq.adr.channel = adr->channel;
err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq);
- printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err);
+ printk(KERN_DEBUG "%s: ret %d (dev %d)\n", __func__, err,
+ dev->id);
if (err)
return err;
write_lock_bh(&dev->D.st->l1sock.lock);
@@ -473,7 +470,7 @@ connect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch,
if (*debug & DEBUG_CORE_FUNC)
printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
- __func__, dev->name, protocol,
+ __func__, dev_name(&dev->dev), protocol,
adr->dev, adr->channel, adr->sapi,
adr->tei);
ch->st = dev->D.st;
@@ -529,7 +526,7 @@ create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch,
if (*debug & DEBUG_CORE_FUNC)
printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
- __func__, dev->name, protocol,
+ __func__, dev_name(&dev->dev), protocol,
adr->dev, adr->channel, adr->sapi,
adr->tei);
rq.protocol = ISDN_P_TE_S0;
@@ -541,15 +538,6 @@ create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch,
if (dev->Dprotocols & (1 << ISDN_P_NT_E1))
rq.protocol = ISDN_P_NT_E1;
case ISDN_P_LAPD_TE:
-#ifdef PROTOCOL_CHECK
- /* this should be enhanced */
- if (!list_empty(&dev->D.st->layer2)
- && dev->D.protocol != protocol)
- return -EBUSY;
- if (!hlist_empty(&dev->D.st->l1sock.head)
- && dev->D.protocol != protocol)
- return -EBUSY;
-#endif
ch->recv = mISDN_queue_message;
ch->peer = &dev->D.st->own;
ch->st = dev->D.st;
@@ -590,7 +578,7 @@ delete_channel(struct mISDNchannel *ch)
}
if (*debug & DEBUG_CORE_FUNC)
printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__,
- ch->st->dev->name, ch->protocol);
+ dev_name(&ch->st->dev->dev), ch->protocol);
if (ch->protocol >= ISDN_P_B_START) {
if (ch->peer) {
ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL);
@@ -643,7 +631,7 @@ delete_stack(struct mISDNdevice *dev)
if (*debug & DEBUG_CORE_FUNC)
printk(KERN_DEBUG "%s: st(%s)\n", __func__,
- st->dev->name);
+ dev_name(&st->dev->dev));
if (dev->teimgr)
delete_teimanager(dev->teimgr);
if (st->thread) {
diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c
index 5c43d19e7c11..b452dead8fd0 100644
--- a/drivers/isdn/mISDN/tei.c
+++ b/drivers/isdn/mISDN/tei.c
@@ -968,9 +968,9 @@ create_teimgr(struct manager *mgr, struct channel_req *crq)
if (*debug & DEBUG_L2_TEI)
printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n",
- __func__, mgr->ch.st->dev->name, crq->protocol,
- crq->adr.dev, crq->adr.channel, crq->adr.sapi,
- crq->adr.tei);
+ __func__, dev_name(&mgr->ch.st->dev->dev),
+ crq->protocol, crq->adr.dev, crq->adr.channel,
+ crq->adr.sapi, crq->adr.tei);
if (crq->adr.sapi != 0) /* not supported yet */
return -EINVAL;
if (crq->adr.tei > GROUP_TEI)
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index e7fb7d2fcbfc..742713611bc5 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -63,6 +63,12 @@ config LEDS_WRAP
help
This option enables support for the PCEngines WRAP programmable LEDs.
+config LEDS_ALIX2
+ tristate "LED Support for ALIX.2 and ALIX.3 series"
+ depends on LEDS_CLASS && X86 && EXPERIMENTAL
+ help
+ This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
+
config LEDS_H1940
tristate "LED Support for iPAQ H1940 device"
depends on LEDS_CLASS && ARCH_H1940
@@ -77,7 +83,7 @@ config LEDS_COBALT_QUBE
config LEDS_COBALT_RAQ
bool "LED Support for the Cobalt Raq series"
- depends on LEDS_CLASS && MIPS_COBALT
+ depends on LEDS_CLASS=y && MIPS_COBALT
select LEDS_TRIGGERS
help
This option enables support for the Cobalt Raq series LEDs.
@@ -113,13 +119,6 @@ config LEDS_GPIO
outputs. To be useful the particular board must have LEDs
and they must be connected to the GPIO lines.
-config LEDS_HP_DISK
- tristate "LED Support for disk protection LED on HP notebooks"
- depends on LEDS_CLASS && ACPI
- help
- This option enable support for disk protection LED, found on
- newer HP notebooks.
-
config LEDS_CLEVO_MAIL
tristate "Mail LED on Clevo notebook (EXPERIMENTAL)"
depends on LEDS_CLASS && X86 && SERIO_I8042 && DMI && EXPERIMENTAL
@@ -158,6 +157,13 @@ config LEDS_PCA955X
LED driver chips accessed via the I2C bus. Supported
devices include PCA9550, PCA9551, PCA9552, and PCA9553.
+config LEDS_WM8350
+ tristate "LED Support for WM8350 AudioPlus PMIC"
+ depends on LEDS_CLASS && MFD_WM8350
+ help
+ This option enables support for LEDs driven by the Wolfson
+ Microelectronics WM8350 AudioPlus PMIC.
+
config LEDS_DA903X
tristate "LED Support for DA9030/DA9034 PMIC"
depends on LEDS_CLASS && PMIC_DA903X
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index e1967a29850e..9d76f0f160a4 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
+obj-$(CONFIG_LEDS_ALIX2) += leds-alix2.o
obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
@@ -22,7 +23,7 @@ obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o
obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o
-obj-$(CONFIG_LEDS_HP_DISK) += leds-hp-disk.o
+obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 6c4a326176d7..52f82e3ea13a 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -91,9 +91,29 @@ void led_classdev_resume(struct led_classdev *led_cdev)
}
EXPORT_SYMBOL_GPL(led_classdev_resume);
+static int led_suspend(struct device *dev, pm_message_t state)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+ if (led_cdev->flags & LED_CORE_SUSPENDRESUME)
+ led_classdev_suspend(led_cdev);
+
+ return 0;
+}
+
+static int led_resume(struct device *dev)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+
+ if (led_cdev->flags & LED_CORE_SUSPENDRESUME)
+ led_classdev_resume(led_cdev);
+
+ return 0;
+}
+
/**
* led_classdev_register - register a new object of led_classdev class.
- * @dev: The device to register.
+ * @parent: The device to register.
* @led_cdev: the led_classdev structure for this device.
*/
int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
@@ -174,6 +194,8 @@ static int __init leds_init(void)
leds_class = class_create(THIS_MODULE, "leds");
if (IS_ERR(leds_class))
return PTR_ERR(leds_class);
+ leds_class->suspend = led_suspend;
+ leds_class->resume = led_resume;
return 0;
}
diff --git a/drivers/leds/leds-alix2.c b/drivers/leds/leds-alix2.c
new file mode 100644
index 000000000000..ddbd7730dfc8
--- /dev/null
+++ b/drivers/leds/leds-alix2.c
@@ -0,0 +1,181 @@
+/*
+ * LEDs driver for PCEngines ALIX.2 and ALIX.3
+ *
+ * Copyright (C) 2008 Constantin Baranov <const@mimas.ru>
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/string.h>
+
+static int force = 0;
+module_param(force, bool, 0444);
+MODULE_PARM_DESC(force, "Assume system has ALIX.2 style LEDs");
+
+struct alix_led {
+ struct led_classdev cdev;
+ unsigned short port;
+ unsigned int on_value;
+ unsigned int off_value;
+};
+
+static void alix_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct alix_led *led_dev =
+ container_of(led_cdev, struct alix_led, cdev);
+
+ if (brightness)
+ outl(led_dev->on_value, led_dev->port);
+ else
+ outl(led_dev->off_value, led_dev->port);
+}
+
+static struct alix_led alix_leds[] = {
+ {
+ .cdev = {
+ .name = "alix:1",
+ .brightness_set = alix_led_set,
+ },
+ .port = 0x6100,
+ .on_value = 1 << 22,
+ .off_value = 1 << 6,
+ },
+ {
+ .cdev = {
+ .name = "alix:2",
+ .brightness_set = alix_led_set,
+ },
+ .port = 0x6180,
+ .on_value = 1 << 25,
+ .off_value = 1 << 9,
+ },
+ {
+ .cdev = {
+ .name = "alix:3",
+ .brightness_set = alix_led_set,
+ },
+ .port = 0x6180,
+ .on_value = 1 << 27,
+ .off_value = 1 << 11,
+ },
+};
+
+static int __init alix_led_probe(struct platform_device *pdev)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(alix_leds); i++) {
+ alix_leds[i].cdev.flags |= LED_CORE_SUSPENDRESUME;
+ ret = led_classdev_register(&pdev->dev, &alix_leds[i].cdev);
+ if (ret < 0)
+ goto fail;
+ }
+ return 0;
+
+fail:
+ while (--i >= 0)
+ led_classdev_unregister(&alix_leds[i].cdev);
+ return ret;
+}
+
+static int alix_led_remove(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(alix_leds); i++)
+ led_classdev_unregister(&alix_leds[i].cdev);
+ return 0;
+}
+
+static struct platform_driver alix_led_driver = {
+ .remove = alix_led_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init alix_present(void)
+{
+ const unsigned long bios_phys = 0x000f0000;
+ const size_t bios_len = 0x00010000;
+ const char alix_sig[] = "PC Engines ALIX.";
+ const size_t alix_sig_len = sizeof(alix_sig) - 1;
+
+ const char *bios_virt;
+ const char *scan_end;
+ const char *p;
+ int ret = 0;
+
+ if (force) {
+ printk(KERN_NOTICE "%s: forced to skip BIOS test, "
+ "assume system has ALIX.2 style LEDs\n",
+ KBUILD_MODNAME);
+ ret = 1;
+ goto out;
+ }
+
+ bios_virt = phys_to_virt(bios_phys);
+ scan_end = bios_virt + bios_len - (alix_sig_len + 2);
+ for (p = bios_virt; p < scan_end; p++) {
+ const char *tail;
+
+ if (memcmp(p, alix_sig, alix_sig_len) != 0) {
+ continue;
+ }
+
+ tail = p + alix_sig_len;
+ if ((tail[0] == '2' || tail[0] == '3') && tail[1] == '\0') {
+ printk(KERN_INFO
+ "%s: system is recognized as \"%s\"\n",
+ KBUILD_MODNAME, p);
+ ret = 1;
+ break;
+ }
+ }
+
+out:
+ return ret;
+}
+
+static struct platform_device *pdev;
+
+static int __init alix_led_init(void)
+{
+ int ret;
+
+ if (!alix_present()) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
+ if (!IS_ERR(pdev)) {
+ ret = platform_driver_probe(&alix_led_driver, alix_led_probe);
+ if (ret)
+ platform_device_unregister(pdev);
+ } else
+ ret = PTR_ERR(pdev);
+
+out:
+ return ret;
+}
+
+static void __exit alix_led_exit(void)
+{
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&alix_led_driver);
+}
+
+module_init(alix_led_init);
+module_exit(alix_led_exit);
+
+MODULE_AUTHOR("Constantin Baranov <const@mimas.ru>");
+MODULE_DESCRIPTION("PCEngines ALIX.2 and ALIX.3 LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-ams-delta.c b/drivers/leds/leds-ams-delta.c
index 1bd590bb3a6e..446050759b4d 100644
--- a/drivers/leds/leds-ams-delta.c
+++ b/drivers/leds/leds-ams-delta.c
@@ -79,37 +79,12 @@ static struct ams_delta_led ams_delta_leds[] = {
},
};
-#ifdef CONFIG_PM
-static int ams_delta_led_suspend(struct platform_device *dev,
- pm_message_t state)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++)
- led_classdev_suspend(&ams_delta_leds[i].cdev);
-
- return 0;
-}
-
-static int ams_delta_led_resume(struct platform_device *dev)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++)
- led_classdev_resume(&ams_delta_leds[i].cdev);
-
- return 0;
-}
-#else
-#define ams_delta_led_suspend NULL
-#define ams_delta_led_resume NULL
-#endif
-
static int ams_delta_led_probe(struct platform_device *pdev)
{
int i, ret;
for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++) {
+ ams_delta_leds[i].cdev.flags |= LED_CORE_SUSPENDRESUME;
ret = led_classdev_register(&pdev->dev,
&ams_delta_leds[i].cdev);
if (ret < 0)
@@ -127,7 +102,7 @@ static int ams_delta_led_remove(struct platform_device *pdev)
{
int i;
- for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i--)
+ for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++)
led_classdev_unregister(&ams_delta_leds[i].cdev);
return 0;
@@ -136,8 +111,6 @@ static int ams_delta_led_remove(struct platform_device *pdev)
static struct platform_driver ams_delta_led_driver = {
.probe = ams_delta_led_probe,
.remove = ams_delta_led_remove,
- .suspend = ams_delta_led_suspend,
- .resume = ams_delta_led_resume,
.driver = {
.name = "ams-delta-led",
.owner = THIS_MODULE,
@@ -151,7 +124,7 @@ static int __init ams_delta_led_init(void)
static void __exit ams_delta_led_exit(void)
{
- return platform_driver_unregister(&ams_delta_led_driver);
+ platform_driver_unregister(&ams_delta_led_driver);
}
module_init(ams_delta_led_init);
diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c
index eb3415e88f43..1813c84ea5fc 100644
--- a/drivers/leds/leds-clevo-mail.c
+++ b/drivers/leds/leds-clevo-mail.c
@@ -142,6 +142,7 @@ static struct led_classdev clevo_mail_led = {
.name = "clevo::mail",
.brightness_set = clevo_mail_led_set,
.blink_set = clevo_mail_led_blink,
+ .flags = LED_CORE_SUSPENDRESUME,
};
static int __init clevo_mail_led_probe(struct platform_device *pdev)
@@ -155,29 +156,9 @@ static int clevo_mail_led_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int clevo_mail_led_suspend(struct platform_device *dev,
- pm_message_t state)
-{
- led_classdev_suspend(&clevo_mail_led);
- return 0;
-}
-
-static int clevo_mail_led_resume(struct platform_device *dev)
-{
- led_classdev_resume(&clevo_mail_led);
- return 0;
-}
-#else
-#define clevo_mail_led_suspend NULL
-#define clevo_mail_led_resume NULL
-#endif
-
static struct platform_driver clevo_mail_led_driver = {
.probe = clevo_mail_led_probe,
.remove = clevo_mail_led_remove,
- .suspend = clevo_mail_led_suspend,
- .resume = clevo_mail_led_resume,
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-fsg.c b/drivers/leds/leds-fsg.c
index 34935155c1c0..5f7c9c5c09b1 100644
--- a/drivers/leds/leds-fsg.c
+++ b/drivers/leds/leds-fsg.c
@@ -99,64 +99,43 @@ static void fsg_led_ring_set(struct led_classdev *led_cdev,
}
-
static struct led_classdev fsg_wlan_led = {
.name = "fsg:blue:wlan",
.brightness_set = fsg_led_wlan_set,
+ .flags = LED_CORE_SUSPENDRESUME,
};
static struct led_classdev fsg_wan_led = {
.name = "fsg:blue:wan",
.brightness_set = fsg_led_wan_set,
+ .flags = LED_CORE_SUSPENDRESUME,
};
static struct led_classdev fsg_sata_led = {
.name = "fsg:blue:sata",
.brightness_set = fsg_led_sata_set,
+ .flags = LED_CORE_SUSPENDRESUME,
};
static struct led_classdev fsg_usb_led = {
.name = "fsg:blue:usb",
.brightness_set = fsg_led_usb_set,
+ .flags = LED_CORE_SUSPENDRESUME,
};
static struct led_classdev fsg_sync_led = {
.name = "fsg:blue:sync",
.brightness_set = fsg_led_sync_set,
+ .flags = LED_CORE_SUSPENDRESUME,
};
static struct led_classdev fsg_ring_led = {
.name = "fsg:blue:ring",
.brightness_set = fsg_led_ring_set,
+ .flags = LED_CORE_SUSPENDRESUME,
};
-
-#ifdef CONFIG_PM
-static int fsg_led_suspend(struct platform_device *dev, pm_message_t state)
-{
- led_classdev_suspend(&fsg_wlan_led);
- led_classdev_suspend(&fsg_wan_led);
- led_classdev_suspend(&fsg_sata_led);
- led_classdev_suspend(&fsg_usb_led);
- led_classdev_suspend(&fsg_sync_led);
- led_classdev_suspend(&fsg_ring_led);
- return 0;
-}
-
-static int fsg_led_resume(struct platform_device *dev)
-{
- led_classdev_resume(&fsg_wlan_led);
- led_classdev_resume(&fsg_wan_led);
- led_classdev_resume(&fsg_sata_led);
- led_classdev_resume(&fsg_usb_led);
- led_classdev_resume(&fsg_sync_led);
- led_classdev_resume(&fsg_ring_led);
- return 0;
-}
-#endif
-
-
static int fsg_led_probe(struct platform_device *pdev)
{
int ret;
@@ -232,10 +211,6 @@ static int fsg_led_remove(struct platform_device *pdev)
static struct platform_driver fsg_led_driver = {
.probe = fsg_led_probe,
.remove = fsg_led_remove,
-#ifdef CONFIG_PM
- .suspend = fsg_led_suspend,
- .resume = fsg_led_resume,
-#endif
.driver = {
.name = "fsg-led",
},
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index b13bd2950e95..2e3df08b649b 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -105,6 +105,7 @@ static int gpio_led_probe(struct platform_device *pdev)
}
led_dat->cdev.brightness_set = gpio_led_set;
led_dat->cdev.brightness = LED_OFF;
+ led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
gpio_direction_output(led_dat->gpio, led_dat->active_low);
@@ -154,44 +155,9 @@ static int __devexit gpio_led_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int gpio_led_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
- struct gpio_led_data *leds_data;
- int i;
-
- leds_data = platform_get_drvdata(pdev);
-
- for (i = 0; i < pdata->num_leds; i++)
- led_classdev_suspend(&leds_data[i].cdev);
-
- return 0;
-}
-
-static int gpio_led_resume(struct platform_device *pdev)
-{
- struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
- struct gpio_led_data *leds_data;
- int i;
-
- leds_data = platform_get_drvdata(pdev);
-
- for (i = 0; i < pdata->num_leds; i++)
- led_classdev_resume(&leds_data[i].cdev);
-
- return 0;
-}
-#else
-#define gpio_led_suspend NULL
-#define gpio_led_resume NULL
-#endif
-
static struct platform_driver gpio_led_driver = {
.probe = gpio_led_probe,
.remove = __devexit_p(gpio_led_remove),
- .suspend = gpio_led_suspend,
- .resume = gpio_led_resume,
.driver = {
.name = "leds-gpio",
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-hp-disk.c b/drivers/leds/leds-hp-disk.c
deleted file mode 100644
index 44fa757d8254..000000000000
--- a/drivers/leds/leds-hp-disk.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * leds-hp-disk.c - driver for HP "hard disk protection" LED
- *
- * Copyright (C) 2008 Pavel Machek
- *
- * 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/init.h>
-#include <linux/dmi.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/kthread.h>
-#include <linux/leds.h>
-#include <acpi/acpi_drivers.h>
-
-#define DRIVER_NAME "leds-hp-disk"
-#define ACPI_MDPS_CLASS "led"
-
-/* For automatic insertion of the module */
-static struct acpi_device_id hpled_device_ids[] = {
- {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
- {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, hpled_device_ids);
-
-struct acpi_hpled {
- struct acpi_device *device; /* The ACPI device */
-};
-
-static struct acpi_hpled adev;
-
-static acpi_status hpled_acpi_write(acpi_handle handle, int reg)
-{
- unsigned long long ret; /* Not used when writing */
- union acpi_object in_obj[1];
- struct acpi_object_list args = { 1, in_obj };
-
- in_obj[0].type = ACPI_TYPE_INTEGER;
- in_obj[0].integer.value = reg;
-
- return acpi_evaluate_integer(handle, "ALED", &args, &ret);
-}
-
-static void hpled_set(struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- hpled_acpi_write(adev.device->handle, !!value);
-}
-
-static struct led_classdev hpled_led = {
- .name = "hp:red:hddprotection",
- .default_trigger = "heartbeat",
- .brightness_set = hpled_set,
-};
-
-#ifdef CONFIG_PM
-static int hpled_suspend(struct acpi_device *dev, pm_message_t state)
-{
- led_classdev_suspend(&hpled_led);
- return 0;
-}
-
-static int hpled_resume(struct acpi_device *dev)
-{
- led_classdev_resume(&hpled_led);
- return 0;
-}
-#else
-#define hpled_suspend NULL
-#define hpled_resume NULL
-#endif
-
-static int hpled_add(struct acpi_device *device)
-{
- int ret;
-
- if (!device)
- return -EINVAL;
-
- adev.device = device;
- strcpy(acpi_device_name(device), DRIVER_NAME);
- strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
- device->driver_data = &adev;
-
- ret = led_classdev_register(NULL, &hpled_led);
- return ret;
-}
-
-static int hpled_remove(struct acpi_device *device, int type)
-{
- if (!device)
- return -EINVAL;
-
- led_classdev_unregister(&hpled_led);
- return 0;
-}
-
-
-
-static struct acpi_driver leds_hp_driver = {
- .name = DRIVER_NAME,
- .class = ACPI_MDPS_CLASS,
- .ids = hpled_device_ids,
- .ops = {
- .add = hpled_add,
- .remove = hpled_remove,
- .suspend = hpled_suspend,
- .resume = hpled_resume,
- }
-};
-
-static int __init hpled_init_module(void)
-{
- int ret;
-
- if (acpi_disabled)
- return -ENODEV;
-
- ret = acpi_bus_register_driver(&leds_hp_driver);
- if (ret < 0)
- return ret;
-
- printk(KERN_INFO DRIVER_NAME " driver loaded.\n");
-
- return 0;
-}
-
-static void __exit hpled_exit_module(void)
-{
- acpi_bus_unregister_driver(&leds_hp_driver);
-}
-
-MODULE_DESCRIPTION("Driver for HP disk protection LED");
-MODULE_AUTHOR("Pavel Machek <pavel@suse.cz>");
-MODULE_LICENSE("GPL");
-
-module_init(hpled_init_module);
-module_exit(hpled_exit_module);
diff --git a/drivers/leds/leds-hp6xx.c b/drivers/leds/leds-hp6xx.c
index e8fb1baf8a50..e4ce1fd46338 100644
--- a/drivers/leds/leds-hp6xx.c
+++ b/drivers/leds/leds-hp6xx.c
@@ -45,30 +45,16 @@ static struct led_classdev hp6xx_red_led = {
.name = "hp6xx:red",
.default_trigger = "hp6xx-charge",
.brightness_set = hp6xxled_red_set,
+ .flags = LED_CORE_SUSPENDRESUME,
};
static struct led_classdev hp6xx_green_led = {
.name = "hp6xx:green",
.default_trigger = "ide-disk",
.brightness_set = hp6xxled_green_set,
+ .flags = LED_CORE_SUSPENDRESUME,
};
-#ifdef CONFIG_PM
-static int hp6xxled_suspend(struct platform_device *dev, pm_message_t state)
-{
- led_classdev_suspend(&hp6xx_red_led);
- led_classdev_suspend(&hp6xx_green_led);
- return 0;
-}
-
-static int hp6xxled_resume(struct platform_device *dev)
-{
- led_classdev_resume(&hp6xx_red_led);
- led_classdev_resume(&hp6xx_green_led);
- return 0;
-}
-#endif
-
static int hp6xxled_probe(struct platform_device *pdev)
{
int ret;
@@ -98,10 +84,6 @@ MODULE_ALIAS("platform:hp6xx-led");
static struct platform_driver hp6xxled_driver = {
.probe = hp6xxled_probe,
.remove = hp6xxled_remove,
-#ifdef CONFIG_PM
- .suspend = hp6xxled_suspend,
- .resume = hp6xxled_resume,
-#endif
.driver = {
.name = "hp6xx-led",
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-net48xx.c b/drivers/leds/leds-net48xx.c
index 054360473c94..93987a12da49 100644
--- a/drivers/leds/leds-net48xx.c
+++ b/drivers/leds/leds-net48xx.c
@@ -33,26 +33,9 @@ static void net48xx_error_led_set(struct led_classdev *led_cdev,
static struct led_classdev net48xx_error_led = {
.name = "net48xx::error",
.brightness_set = net48xx_error_led_set,
+ .flags = LED_CORE_SUSPENDRESUME,
};
-#ifdef CONFIG_PM
-static int net48xx_led_suspend(struct platform_device *dev,
- pm_message_t state)
-{
- led_classdev_suspend(&net48xx_error_led);
- return 0;
-}
-
-static int net48xx_led_resume(struct platform_device *dev)
-{
- led_classdev_resume(&net48xx_error_led);
- return 0;
-}
-#else
-#define net48xx_led_suspend NULL
-#define net48xx_led_resume NULL
-#endif
-
static int net48xx_led_probe(struct platform_device *pdev)
{
return led_classdev_register(&pdev->dev, &net48xx_error_led);
@@ -67,8 +50,6 @@ static int net48xx_led_remove(struct platform_device *pdev)
static struct platform_driver net48xx_led_driver = {
.probe = net48xx_led_probe,
.remove = net48xx_led_remove,
- .suspend = net48xx_led_suspend,
- .resume = net48xx_led_resume,
.driver = {
.name = DRVNAME,
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index 4064d4f6b33b..76ec7498e2d5 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -16,6 +16,7 @@
#include <linux/leds.h>
#include <linux/input.h>
#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include <linux/leds-pca9532.h>
static const unsigned short normal_i2c[] = { /*0x60,*/ I2C_CLIENT_END};
@@ -34,6 +35,7 @@ struct pca9532_data {
struct pca9532_led leds[16];
struct mutex update_lock;
struct input_dev *idev;
+ struct work_struct work;
u8 pwm[2];
u8 psc[2];
};
@@ -63,7 +65,7 @@ static struct i2c_driver pca9532_driver = {
* as a compromise we average one pwm to the values requested by all
* leds that are not ON/OFF.
* */
-static int pca9532_setpwm(struct i2c_client *client, int pwm, int blink,
+static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink,
enum led_brightness value)
{
int a = 0, b = 0, i = 0;
@@ -84,11 +86,17 @@ static int pca9532_setpwm(struct i2c_client *client, int pwm, int blink,
b = b/a;
if (b > 0xFF)
return -EINVAL;
- mutex_lock(&data->update_lock);
data->pwm[pwm] = b;
+ data->psc[pwm] = blink;
+ return 0;
+}
+
+static int pca9532_setpwm(struct i2c_client *client, int pwm)
+{
+ struct pca9532_data *data = i2c_get_clientdata(client);
+ mutex_lock(&data->update_lock);
i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm),
data->pwm[pwm]);
- data->psc[pwm] = blink;
i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm),
data->psc[pwm]);
mutex_unlock(&data->update_lock);
@@ -124,11 +132,11 @@ static void pca9532_set_brightness(struct led_classdev *led_cdev,
led->state = PCA9532_ON;
else {
led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */
- err = pca9532_setpwm(led->client, 0, 0, value);
+ err = pca9532_calcpwm(led->client, 0, 0, value);
if (err)
return; /* XXX: led api doesn't allow error code? */
}
- pca9532_setled(led);
+ schedule_work(&led->work);
}
static int pca9532_set_blink(struct led_classdev *led_cdev,
@@ -137,6 +145,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
struct pca9532_led *led = ldev_to_led(led_cdev);
struct i2c_client *client = led->client;
int psc;
+ int err = 0;
if (*delay_on == 0 && *delay_off == 0) {
/* led subsystem ask us for a blink rate */
@@ -148,11 +157,15 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
/* Thecus specific: only use PSC/PWM 0 */
psc = (*delay_on * 152-1)/1000;
- return pca9532_setpwm(client, 0, psc, led_cdev->brightness);
+ err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness);
+ if (err)
+ return err;
+ schedule_work(&led->work);
+ return 0;
}
-int pca9532_event(struct input_dev *dev, unsigned int type, unsigned int code,
- int value)
+static int pca9532_event(struct input_dev *dev, unsigned int type,
+ unsigned int code, int value)
{
struct pca9532_data *data = input_get_drvdata(dev);
@@ -165,13 +178,28 @@ int pca9532_event(struct input_dev *dev, unsigned int type, unsigned int code,
else
data->pwm[1] = 0;
- dev_info(&dev->dev, "setting beep to %d \n", data->pwm[1]);
+ schedule_work(&data->work);
+
+ return 0;
+}
+
+static void pca9532_input_work(struct work_struct *work)
+{
+ struct pca9532_data *data;
+ data = container_of(work, struct pca9532_data, work);
mutex_lock(&data->update_lock);
i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1),
data->pwm[1]);
mutex_unlock(&data->update_lock);
+}
- return 0;
+static void pca9532_led_work(struct work_struct *work)
+{
+ struct pca9532_led *led;
+ led = container_of(work, struct pca9532_led, work);
+ if (led->state == PCA9532_PWM0)
+ pca9532_setpwm(led->client, 0);
+ pca9532_setled(led);
}
static int pca9532_configure(struct i2c_client *client,
@@ -204,8 +232,9 @@ static int pca9532_configure(struct i2c_client *client,
led->ldev.brightness = LED_OFF;
led->ldev.brightness_set = pca9532_set_brightness;
led->ldev.blink_set = pca9532_set_blink;
- if (led_classdev_register(&client->dev,
- &led->ldev) < 0) {
+ INIT_WORK(&led->work, pca9532_led_work);
+ err = led_classdev_register(&client->dev, &led->ldev);
+ if (err < 0) {
dev_err(&client->dev,
"couldn't register LED %s\n",
led->name);
@@ -233,9 +262,11 @@ static int pca9532_configure(struct i2c_client *client,
BIT_MASK(SND_TONE);
data->idev->event = pca9532_event;
input_set_drvdata(data->idev, data);
+ INIT_WORK(&data->work, pca9532_input_work);
err = input_register_device(data->idev);
if (err) {
input_free_device(data->idev);
+ cancel_work_sync(&data->work);
data->idev = NULL;
goto exit;
}
@@ -252,18 +283,19 @@ exit:
break;
case PCA9532_TYPE_LED:
led_classdev_unregister(&data->leds[i].ldev);
+ cancel_work_sync(&data->leds[i].work);
break;
case PCA9532_TYPE_N2100_BEEP:
if (data->idev != NULL) {
input_unregister_device(data->idev);
input_free_device(data->idev);
+ cancel_work_sync(&data->work);
data->idev = NULL;
}
break;
}
return err;
-
}
static int pca9532_probe(struct i2c_client *client,
@@ -271,12 +303,16 @@ static int pca9532_probe(struct i2c_client *client,
{
struct pca9532_data *data = i2c_get_clientdata(client);
struct pca9532_platform_data *pca9532_pdata = client->dev.platform_data;
+ int err;
+
+ if (!pca9532_pdata)
+ return -EIO;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- data = kzalloc(sizeof(struct pca9532_data), GFP_KERNEL);
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -285,12 +321,13 @@ static int pca9532_probe(struct i2c_client *client,
data->client = client;
mutex_init(&data->update_lock);
- if (pca9532_pdata == NULL)
- return -EIO;
-
- pca9532_configure(client, data, pca9532_pdata);
- return 0;
+ err = pca9532_configure(client, data, pca9532_pdata);
+ if (err) {
+ kfree(data);
+ i2c_set_clientdata(client, NULL);
+ }
+ return err;
}
static int pca9532_remove(struct i2c_client *client)
@@ -303,11 +340,13 @@ static int pca9532_remove(struct i2c_client *client)
break;
case PCA9532_TYPE_LED:
led_classdev_unregister(&data->leds[i].ldev);
+ cancel_work_sync(&data->leds[i].work);
break;
case PCA9532_TYPE_N2100_BEEP:
if (data->idev != NULL) {
input_unregister_device(data->idev);
input_free_device(data->idev);
+ cancel_work_sync(&data->work);
data->idev = NULL;
}
break;
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index 25a07f2643ad..4d81131542ae 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -82,6 +82,7 @@ static int s3c24xx_led_probe(struct platform_device *dev)
led->cdev.brightness_set = s3c24xx_led_set;
led->cdev.default_trigger = pdata->def_trigger;
led->cdev.name = pdata->name;
+ led->cdev.flags |= LED_CORE_SUSPENDRESUME;
led->pdata = pdata;
@@ -111,33 +112,9 @@ static int s3c24xx_led_probe(struct platform_device *dev)
return ret;
}
-
-#ifdef CONFIG_PM
-static int s3c24xx_led_suspend(struct platform_device *dev, pm_message_t state)
-{
- struct s3c24xx_gpio_led *led = pdev_to_gpio(dev);
-
- led_classdev_suspend(&led->cdev);
- return 0;
-}
-
-static int s3c24xx_led_resume(struct platform_device *dev)
-{
- struct s3c24xx_gpio_led *led = pdev_to_gpio(dev);
-
- led_classdev_resume(&led->cdev);
- return 0;
-}
-#else
-#define s3c24xx_led_suspend NULL
-#define s3c24xx_led_resume NULL
-#endif
-
static struct platform_driver s3c24xx_led_driver = {
.probe = s3c24xx_led_probe,
.remove = s3c24xx_led_remove,
- .suspend = s3c24xx_led_suspend,
- .resume = s3c24xx_led_resume,
.driver = {
.name = "s3c24xx_led",
.owner = THIS_MODULE,
diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c
new file mode 100644
index 000000000000..38c6bcb07e6c
--- /dev/null
+++ b/drivers/leds/leds-wm8350.c
@@ -0,0 +1,311 @@
+/*
+ * LED driver for WM8350 driven LEDS.
+ *
+ * Copyright(C) 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/regulator/consumer.h>
+
+/* Microamps */
+static const int isink_cur[] = {
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 10,
+ 11,
+ 14,
+ 16,
+ 19,
+ 23,
+ 27,
+ 32,
+ 39,
+ 46,
+ 54,
+ 65,
+ 77,
+ 92,
+ 109,
+ 130,
+ 154,
+ 183,
+ 218,
+ 259,
+ 308,
+ 367,
+ 436,
+ 518,
+ 616,
+ 733,
+ 872,
+ 1037,
+ 1233,
+ 1466,
+ 1744,
+ 2073,
+ 2466,
+ 2933,
+ 3487,
+ 4147,
+ 4932,
+ 5865,
+ 6975,
+ 8294,
+ 9864,
+ 11730,
+ 13949,
+ 16589,
+ 19728,
+ 23460,
+ 27899,
+ 33178,
+ 39455,
+ 46920,
+ 55798,
+ 66355,
+ 78910,
+ 93840,
+ 111596,
+ 132710,
+ 157820,
+ 187681,
+ 223191
+};
+
+#define to_wm8350_led(led_cdev) \
+ container_of(led_cdev, struct wm8350_led, cdev)
+
+static void wm8350_led_enable(struct wm8350_led *led)
+{
+ int ret;
+
+ if (led->enabled)
+ return;
+
+ ret = regulator_enable(led->isink);
+ if (ret != 0) {
+ dev_err(led->cdev.dev, "Failed to enable ISINK: %d\n", ret);
+ return;
+ }
+
+ ret = regulator_enable(led->dcdc);
+ if (ret != 0) {
+ dev_err(led->cdev.dev, "Failed to enable DCDC: %d\n", ret);
+ regulator_disable(led->isink);
+ return;
+ }
+
+ led->enabled = 1;
+}
+
+static void wm8350_led_disable(struct wm8350_led *led)
+{
+ int ret;
+
+ if (!led->enabled)
+ return;
+
+ ret = regulator_disable(led->dcdc);
+ if (ret != 0) {
+ dev_err(led->cdev.dev, "Failed to disable DCDC: %d\n", ret);
+ return;
+ }
+
+ ret = regulator_disable(led->isink);
+ if (ret != 0) {
+ dev_err(led->cdev.dev, "Failed to disable ISINK: %d\n", ret);
+ regulator_enable(led->dcdc);
+ return;
+ }
+
+ led->enabled = 0;
+}
+
+static void led_work(struct work_struct *work)
+{
+ struct wm8350_led *led = container_of(work, struct wm8350_led, work);
+ int ret;
+ int uA;
+ unsigned long flags;
+
+ mutex_lock(&led->mutex);
+
+ spin_lock_irqsave(&led->value_lock, flags);
+
+ if (led->value == LED_OFF) {
+ spin_unlock_irqrestore(&led->value_lock, flags);
+ wm8350_led_disable(led);
+ goto out;
+ }
+
+ /* This scales linearly into the index of valid current
+ * settings which results in a linear scaling of perceived
+ * brightness due to the non-linear current settings provided
+ * by the hardware.
+ */
+ uA = (led->max_uA_index * led->value) / LED_FULL;
+ spin_unlock_irqrestore(&led->value_lock, flags);
+ BUG_ON(uA >= ARRAY_SIZE(isink_cur));
+
+ ret = regulator_set_current_limit(led->isink, isink_cur[uA],
+ isink_cur[uA]);
+ if (ret != 0)
+ dev_err(led->cdev.dev, "Failed to set %duA: %d\n",
+ isink_cur[uA], ret);
+
+ wm8350_led_enable(led);
+
+out:
+ mutex_unlock(&led->mutex);
+}
+
+static void wm8350_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct wm8350_led *led = to_wm8350_led(led_cdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&led->value_lock, flags);
+ led->value = value;
+ schedule_work(&led->work);
+ spin_unlock_irqrestore(&led->value_lock, flags);
+}
+
+static void wm8350_led_shutdown(struct platform_device *pdev)
+{
+ struct wm8350_led *led = platform_get_drvdata(pdev);
+
+ mutex_lock(&led->mutex);
+ led->value = LED_OFF;
+ wm8350_led_disable(led);
+ mutex_unlock(&led->mutex);
+}
+
+static int wm8350_led_probe(struct platform_device *pdev)
+{
+ struct regulator *isink, *dcdc;
+ struct wm8350_led *led;
+ struct wm8350_led_platform_data *pdata = pdev->dev.platform_data;
+ int ret, i;
+
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -ENODEV;
+ }
+
+ if (pdata->max_uA < isink_cur[0]) {
+ dev_err(&pdev->dev, "Invalid maximum current %duA\n",
+ pdata->max_uA);
+ return -EINVAL;
+ }
+
+ isink = regulator_get(&pdev->dev, "led_isink");
+ if (IS_ERR(isink)) {
+ printk(KERN_ERR "%s: cant get ISINK\n", __func__);
+ return PTR_ERR(isink);
+ }
+
+ dcdc = regulator_get(&pdev->dev, "led_vcc");
+ if (IS_ERR(dcdc)) {
+ printk(KERN_ERR "%s: cant get DCDC\n", __func__);
+ ret = PTR_ERR(dcdc);
+ goto err_isink;
+ }
+
+ led = kzalloc(sizeof(*led), GFP_KERNEL);
+ if (led == NULL) {
+ ret = -ENOMEM;
+ goto err_dcdc;
+ }
+
+ led->cdev.brightness_set = wm8350_led_set;
+ led->cdev.default_trigger = pdata->default_trigger;
+ led->cdev.name = pdata->name;
+ led->cdev.flags |= LED_CORE_SUSPENDRESUME;
+ led->enabled = regulator_is_enabled(isink);
+ led->isink = isink;
+ led->dcdc = dcdc;
+
+ for (i = 0; i < ARRAY_SIZE(isink_cur) - 1; i++)
+ if (isink_cur[i] >= pdata->max_uA)
+ break;
+ led->max_uA_index = i;
+ if (pdata->max_uA != isink_cur[i])
+ dev_warn(&pdev->dev,
+ "Maximum current %duA is not directly supported,"
+ " check platform data\n",
+ pdata->max_uA);
+
+ spin_lock_init(&led->value_lock);
+ mutex_init(&led->mutex);
+ INIT_WORK(&led->work, led_work);
+ led->value = LED_OFF;
+ platform_set_drvdata(pdev, led);
+
+ ret = led_classdev_register(&pdev->dev, &led->cdev);
+ if (ret < 0)
+ goto err_led;
+
+ return 0;
+
+ err_led:
+ kfree(led);
+ err_dcdc:
+ regulator_put(dcdc);
+ err_isink:
+ regulator_put(isink);
+ return ret;
+}
+
+static int wm8350_led_remove(struct platform_device *pdev)
+{
+ struct wm8350_led *led = platform_get_drvdata(pdev);
+
+ led_classdev_unregister(&led->cdev);
+ flush_scheduled_work();
+ wm8350_led_disable(led);
+ regulator_put(led->dcdc);
+ regulator_put(led->isink);
+ kfree(led);
+ return 0;
+}
+
+static struct platform_driver wm8350_led_driver = {
+ .driver = {
+ .name = "wm8350-led",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8350_led_probe,
+ .remove = wm8350_led_remove,
+ .shutdown = wm8350_led_shutdown,
+};
+
+static int __devinit wm8350_led_init(void)
+{
+ return platform_driver_register(&wm8350_led_driver);
+}
+module_init(wm8350_led_init);
+
+static void wm8350_led_exit(void)
+{
+ platform_driver_unregister(&wm8350_led_driver);
+}
+module_exit(wm8350_led_exit);
+
+MODULE_AUTHOR("Mark Brown");
+MODULE_DESCRIPTION("WM8350 LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8350-led");
diff --git a/drivers/leds/leds-wrap.c b/drivers/leds/leds-wrap.c
index 2f3aa87f2a1f..2982c86ac4cf 100644
--- a/drivers/leds/leds-wrap.c
+++ b/drivers/leds/leds-wrap.c
@@ -56,40 +56,21 @@ static struct led_classdev wrap_power_led = {
.name = "wrap::power",
.brightness_set = wrap_power_led_set,
.default_trigger = "default-on",
+ .flags = LED_CORE_SUSPENDRESUME,
};
static struct led_classdev wrap_error_led = {
.name = "wrap::error",
.brightness_set = wrap_error_led_set,
+ .flags = LED_CORE_SUSPENDRESUME,
};
static struct led_classdev wrap_extra_led = {
.name = "wrap::extra",
.brightness_set = wrap_extra_led_set,
+ .flags = LED_CORE_SUSPENDRESUME,
};
-#ifdef CONFIG_PM
-static int wrap_led_suspend(struct platform_device *dev,
- pm_message_t state)
-{
- led_classdev_suspend(&wrap_power_led);
- led_classdev_suspend(&wrap_error_led);
- led_classdev_suspend(&wrap_extra_led);
- return 0;
-}
-
-static int wrap_led_resume(struct platform_device *dev)
-{
- led_classdev_resume(&wrap_power_led);
- led_classdev_resume(&wrap_error_led);
- led_classdev_resume(&wrap_extra_led);
- return 0;
-}
-#else
-#define wrap_led_suspend NULL
-#define wrap_led_resume NULL
-#endif
-
static int wrap_led_probe(struct platform_device *pdev)
{
int ret;
@@ -127,8 +108,6 @@ static int wrap_led_remove(struct platform_device *pdev)
static struct platform_driver wrap_led_driver = {
.probe = wrap_led_probe,
.remove = wrap_led_remove,
- .suspend = wrap_led_suspend,
- .resume = wrap_led_resume,
.driver = {
.name = DRVNAME,
.owner = THIS_MODULE,
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index db681962d7bb..3d6531396dda 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -199,6 +199,7 @@ err_out:
static void timer_trig_deactivate(struct led_classdev *led_cdev)
{
struct timer_trig_data *timer_data = led_cdev->trigger_data;
+ unsigned long on = 0, off = 0;
if (timer_data) {
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
@@ -206,6 +207,10 @@ static void timer_trig_deactivate(struct led_classdev *led_cdev)
del_timer_sync(&timer_data->timer);
kfree(timer_data);
}
+
+ /* If there is hardware support for blinking, stop it */
+ if (led_cdev->blink_set)
+ led_cdev->blink_set(led_cdev, &on, &off);
}
static struct led_trigger timer_led_trigger = {
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index b52659620d50..173cf55c64d0 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -138,7 +138,7 @@ config PMAC_BACKLIGHT
Say Y here to enable Macintosh specific extensions of the generic
backlight code. With this enabled, the brightness keys on older
PowerBooks will be enabled so you can change the screen brightness.
- Newer models should use an userspace daemon like pbbuttonsd.
+ Newer models should use a userspace daemon like pbbuttonsd.
config PMAC_BACKLIGHT_LEGACY
bool "Provide legacy ioctl's on /dev/pmu for the backlight"
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index ab7c8e4a61f9..719943763391 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -215,7 +215,6 @@ static struct page *read_sb_page(mddev_t *mddev, long offset,
/* choose a good rdev and read the page from there */
mdk_rdev_t *rdev;
- struct list_head *tmp;
sector_t target;
if (!page)
@@ -223,7 +222,7 @@ static struct page *read_sb_page(mddev_t *mddev, long offset,
if (!page)
return ERR_PTR(-ENOMEM);
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
if (! test_bit(In_sync, &rdev->flags)
|| test_bit(Faulty, &rdev->flags))
continue;
@@ -964,9 +963,11 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
*/
page = bitmap->sb_page;
offset = sizeof(bitmap_super_t);
- read_sb_page(bitmap->mddev, bitmap->offset,
- page,
- index, count);
+ if (!file)
+ read_sb_page(bitmap->mddev,
+ bitmap->offset,
+ page,
+ index, count);
} else if (file) {
page = read_page(file, index, bitmap, count);
offset = 0;
diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c
index f26c1f9a475b..86d9adf90e79 100644
--- a/drivers/md/faulty.c
+++ b/drivers/md/faulty.c
@@ -283,7 +283,6 @@ static int reconfig(mddev_t *mddev, int layout, int chunk_size)
static int run(mddev_t *mddev)
{
mdk_rdev_t *rdev;
- struct list_head *tmp;
int i;
conf_t *conf = kmalloc(sizeof(*conf), GFP_KERNEL);
@@ -296,7 +295,7 @@ static int run(mddev_t *mddev)
}
conf->nfaults = 0;
- rdev_for_each(rdev, tmp, mddev)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
conf->rdev = rdev;
mddev->array_sectors = mddev->size * 2;
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 3b90c5c924ec..1e3aea9eecf1 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -105,7 +105,6 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
int i, nb_zone, cnt;
sector_t min_sectors;
sector_t curr_sector;
- struct list_head *tmp;
conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(dev_info_t),
GFP_KERNEL);
@@ -115,7 +114,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
cnt = 0;
conf->array_sectors = 0;
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
int j = rdev->raid_disk;
dev_info_t *disk = conf->disks + j;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 1b1d32694f6f..41e2509bf896 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -214,20 +214,33 @@ static inline mddev_t *mddev_get(mddev_t *mddev)
return mddev;
}
+static void mddev_delayed_delete(struct work_struct *ws)
+{
+ mddev_t *mddev = container_of(ws, mddev_t, del_work);
+ kobject_del(&mddev->kobj);
+ kobject_put(&mddev->kobj);
+}
+
static void mddev_put(mddev_t *mddev)
{
if (!atomic_dec_and_lock(&mddev->active, &all_mddevs_lock))
return;
- if (!mddev->raid_disks && list_empty(&mddev->disks)) {
+ if (!mddev->raid_disks && list_empty(&mddev->disks) &&
+ !mddev->hold_active) {
list_del(&mddev->all_mddevs);
- spin_unlock(&all_mddevs_lock);
- blk_cleanup_queue(mddev->queue);
- if (mddev->sysfs_state)
- sysfs_put(mddev->sysfs_state);
- mddev->sysfs_state = NULL;
- kobject_put(&mddev->kobj);
- } else
- spin_unlock(&all_mddevs_lock);
+ if (mddev->gendisk) {
+ /* we did a probe so need to clean up.
+ * Call schedule_work inside the spinlock
+ * so that flush_scheduled_work() after
+ * mddev_find will succeed in waiting for the
+ * work to be done.
+ */
+ INIT_WORK(&mddev->del_work, mddev_delayed_delete);
+ schedule_work(&mddev->del_work);
+ } else
+ kfree(mddev);
+ }
+ spin_unlock(&all_mddevs_lock);
}
static mddev_t * mddev_find(dev_t unit)
@@ -236,15 +249,50 @@ static mddev_t * mddev_find(dev_t unit)
retry:
spin_lock(&all_mddevs_lock);
- list_for_each_entry(mddev, &all_mddevs, all_mddevs)
- if (mddev->unit == unit) {
- mddev_get(mddev);
+
+ if (unit) {
+ list_for_each_entry(mddev, &all_mddevs, all_mddevs)
+ if (mddev->unit == unit) {
+ mddev_get(mddev);
+ spin_unlock(&all_mddevs_lock);
+ kfree(new);
+ return mddev;
+ }
+
+ if (new) {
+ list_add(&new->all_mddevs, &all_mddevs);
spin_unlock(&all_mddevs_lock);
- kfree(new);
- return mddev;
+ new->hold_active = UNTIL_IOCTL;
+ return new;
}
-
- if (new) {
+ } else if (new) {
+ /* find an unused unit number */
+ static int next_minor = 512;
+ int start = next_minor;
+ int is_free = 0;
+ int dev = 0;
+ while (!is_free) {
+ dev = MKDEV(MD_MAJOR, next_minor);
+ next_minor++;
+ if (next_minor > MINORMASK)
+ next_minor = 0;
+ if (next_minor == start) {
+ /* Oh dear, all in use. */
+ spin_unlock(&all_mddevs_lock);
+ kfree(new);
+ return NULL;
+ }
+
+ is_free = 1;
+ list_for_each_entry(mddev, &all_mddevs, all_mddevs)
+ if (mddev->unit == dev) {
+ is_free = 0;
+ break;
+ }
+ }
+ new->unit = dev;
+ new->md_minor = MINOR(dev);
+ new->hold_active = UNTIL_STOP;
list_add(&new->all_mddevs, &all_mddevs);
spin_unlock(&all_mddevs_lock);
return new;
@@ -275,16 +323,6 @@ static mddev_t * mddev_find(dev_t unit)
new->resync_max = MaxSector;
new->level = LEVEL_NONE;
- new->queue = blk_alloc_queue(GFP_KERNEL);
- if (!new->queue) {
- kfree(new);
- return NULL;
- }
- /* Can be unlocked because the queue is new: no concurrency */
- queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, new->queue);
-
- blk_queue_make_request(new->queue, md_fail_request);
-
goto retry;
}
@@ -307,25 +345,23 @@ static inline void mddev_unlock(mddev_t * mddev)
static mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr)
{
- mdk_rdev_t * rdev;
- struct list_head *tmp;
+ mdk_rdev_t *rdev;
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->desc_nr == nr)
return rdev;
- }
+
return NULL;
}
static mdk_rdev_t * find_rdev(mddev_t * mddev, dev_t dev)
{
- struct list_head *tmp;
mdk_rdev_t *rdev;
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->bdev->bd_dev == dev)
return rdev;
- }
+
return NULL;
}
@@ -861,7 +897,6 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
{
mdp_super_t *sb;
- struct list_head *tmp;
mdk_rdev_t *rdev2;
int next_spare = mddev->raid_disks;
@@ -933,7 +968,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->state |= (1<<MD_SB_BITMAP_PRESENT);
sb->disks[0].state = (1<<MD_DISK_REMOVED);
- rdev_for_each(rdev2, tmp, mddev) {
+ list_for_each_entry(rdev2, &mddev->disks, same_set) {
mdp_disk_t *d;
int desc_nr;
if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags)
@@ -1259,7 +1294,6 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
{
struct mdp_superblock_1 *sb;
- struct list_head *tmp;
mdk_rdev_t *rdev2;
int max_dev, i;
/* make rdev->sb match mddev and rdev data. */
@@ -1307,7 +1341,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
}
max_dev = 0;
- rdev_for_each(rdev2, tmp, mddev)
+ list_for_each_entry(rdev2, &mddev->disks, same_set)
if (rdev2->desc_nr+1 > max_dev)
max_dev = rdev2->desc_nr+1;
@@ -1316,7 +1350,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
for (i=0; i<max_dev;i++)
sb->dev_roles[i] = cpu_to_le16(0xfffe);
- rdev_for_each(rdev2, tmp, mddev) {
+ list_for_each_entry(rdev2, &mddev->disks, same_set) {
i = rdev2->desc_nr;
if (test_bit(Faulty, &rdev2->flags))
sb->dev_roles[i] = cpu_to_le16(0xfffe);
@@ -1466,6 +1500,9 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
list_add_rcu(&rdev->same_set, &mddev->disks);
bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk);
+
+ /* May as well allow recovery to be retried once */
+ mddev->recovery_disabled = 0;
return 0;
fail:
@@ -1571,8 +1608,7 @@ static void kick_rdev_from_array(mdk_rdev_t * rdev)
static void export_array(mddev_t *mddev)
{
- struct list_head *tmp;
- mdk_rdev_t *rdev;
+ mdk_rdev_t *rdev, *tmp;
rdev_for_each(rdev, tmp, mddev) {
if (!rdev->mddev) {
@@ -1593,7 +1629,7 @@ static void print_desc(mdp_disk_t *desc)
desc->major,desc->minor,desc->raid_disk,desc->state);
}
-static void print_sb(mdp_super_t *sb)
+static void print_sb_90(mdp_super_t *sb)
{
int i;
@@ -1624,10 +1660,57 @@ static void print_sb(mdp_super_t *sb)
}
printk(KERN_INFO "md: THIS: ");
print_desc(&sb->this_disk);
-
}
-static void print_rdev(mdk_rdev_t *rdev)
+static void print_sb_1(struct mdp_superblock_1 *sb)
+{
+ __u8 *uuid;
+
+ uuid = sb->set_uuid;
+ printk(KERN_INFO "md: SB: (V:%u) (F:0x%08x) Array-ID:<%02x%02x%02x%02x"
+ ":%02x%02x:%02x%02x:%02x%02x:%02x%02x%02x%02x%02x%02x>\n"
+ KERN_INFO "md: Name: \"%s\" CT:%llu\n",
+ le32_to_cpu(sb->major_version),
+ le32_to_cpu(sb->feature_map),
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15],
+ sb->set_name,
+ (unsigned long long)le64_to_cpu(sb->ctime)
+ & MD_SUPERBLOCK_1_TIME_SEC_MASK);
+
+ uuid = sb->device_uuid;
+ printk(KERN_INFO "md: L%u SZ%llu RD:%u LO:%u CS:%u DO:%llu DS:%llu SO:%llu"
+ " RO:%llu\n"
+ KERN_INFO "md: Dev:%08x UUID: %02x%02x%02x%02x:%02x%02x:%02x%02x:%02x%02x"
+ ":%02x%02x%02x%02x%02x%02x\n"
+ KERN_INFO "md: (F:0x%08x) UT:%llu Events:%llu ResyncOffset:%llu CSUM:0x%08x\n"
+ KERN_INFO "md: (MaxDev:%u) \n",
+ le32_to_cpu(sb->level),
+ (unsigned long long)le64_to_cpu(sb->size),
+ le32_to_cpu(sb->raid_disks),
+ le32_to_cpu(sb->layout),
+ le32_to_cpu(sb->chunksize),
+ (unsigned long long)le64_to_cpu(sb->data_offset),
+ (unsigned long long)le64_to_cpu(sb->data_size),
+ (unsigned long long)le64_to_cpu(sb->super_offset),
+ (unsigned long long)le64_to_cpu(sb->recovery_offset),
+ le32_to_cpu(sb->dev_number),
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15],
+ sb->devflags,
+ (unsigned long long)le64_to_cpu(sb->utime) & MD_SUPERBLOCK_1_TIME_SEC_MASK,
+ (unsigned long long)le64_to_cpu(sb->events),
+ (unsigned long long)le64_to_cpu(sb->resync_offset),
+ le32_to_cpu(sb->sb_csum),
+ le32_to_cpu(sb->max_dev)
+ );
+}
+
+static void print_rdev(mdk_rdev_t *rdev, int major_version)
{
char b[BDEVNAME_SIZE];
printk(KERN_INFO "md: rdev %s, SZ:%08llu F:%d S:%d DN:%u\n",
@@ -1635,15 +1718,22 @@ static void print_rdev(mdk_rdev_t *rdev)
test_bit(Faulty, &rdev->flags), test_bit(In_sync, &rdev->flags),
rdev->desc_nr);
if (rdev->sb_loaded) {
- printk(KERN_INFO "md: rdev superblock:\n");
- print_sb((mdp_super_t*)page_address(rdev->sb_page));
+ printk(KERN_INFO "md: rdev superblock (MJ:%d):\n", major_version);
+ switch (major_version) {
+ case 0:
+ print_sb_90((mdp_super_t*)page_address(rdev->sb_page));
+ break;
+ case 1:
+ print_sb_1((struct mdp_superblock_1 *)page_address(rdev->sb_page));
+ break;
+ }
} else
printk(KERN_INFO "md: no rdev superblock!\n");
}
static void md_print_devices(void)
{
- struct list_head *tmp, *tmp2;
+ struct list_head *tmp;
mdk_rdev_t *rdev;
mddev_t *mddev;
char b[BDEVNAME_SIZE];
@@ -1658,12 +1748,12 @@ static void md_print_devices(void)
bitmap_print_sb(mddev->bitmap);
else
printk("%s: ", mdname(mddev));
- rdev_for_each(rdev, tmp2, mddev)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
printk("<%s>", bdevname(rdev->bdev,b));
printk("\n");
- rdev_for_each(rdev, tmp2, mddev)
- print_rdev(rdev);
+ list_for_each_entry(rdev, &mddev->disks, same_set)
+ print_rdev(rdev, mddev->major_version);
}
printk("md: **********************************\n");
printk("\n");
@@ -1679,9 +1769,8 @@ static void sync_sbs(mddev_t * mddev, int nospares)
* with the rest of the array)
*/
mdk_rdev_t *rdev;
- struct list_head *tmp;
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
if (rdev->sb_events == mddev->events ||
(nospares &&
rdev->raid_disk < 0 &&
@@ -1699,7 +1788,6 @@ static void sync_sbs(mddev_t * mddev, int nospares)
static void md_update_sb(mddev_t * mddev, int force_change)
{
- struct list_head *tmp;
mdk_rdev_t *rdev;
int sync_req;
int nospares = 0;
@@ -1790,7 +1878,7 @@ repeat:
mdname(mddev),mddev->in_sync);
bitmap_update_sb(mddev->bitmap);
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
char b[BDEVNAME_SIZE];
dprintk(KERN_INFO "md: ");
if (rdev->sb_loaded != 1)
@@ -1999,7 +2087,6 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
md_wakeup_thread(rdev->mddev->thread);
} else if (rdev->mddev->pers) {
mdk_rdev_t *rdev2;
- struct list_head *tmp;
/* Activating a spare .. or possibly reactivating
* if we every get bitmaps working here.
*/
@@ -2010,7 +2097,7 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
if (rdev->mddev->pers->hot_add_disk == NULL)
return -EINVAL;
- rdev_for_each(rdev2, tmp, rdev->mddev)
+ list_for_each_entry(rdev2, &rdev->mddev->disks, same_set)
if (rdev2->raid_disk == slot)
return -EEXIST;
@@ -2125,14 +2212,14 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
*/
mddev_t *mddev;
int overlap = 0;
- struct list_head *tmp, *tmp2;
+ struct list_head *tmp;
mddev_unlock(my_mddev);
for_each_mddev(mddev, tmp) {
mdk_rdev_t *rdev2;
mddev_lock(mddev);
- rdev_for_each(rdev2, tmp2, mddev)
+ list_for_each_entry(rdev2, &mddev->disks, same_set)
if (test_bit(AllReserved, &rdev2->flags) ||
(rdev->bdev == rdev2->bdev &&
rdev != rdev2 &&
@@ -2328,8 +2415,7 @@ abort_free:
static void analyze_sbs(mddev_t * mddev)
{
int i;
- struct list_head *tmp;
- mdk_rdev_t *rdev, *freshest;
+ mdk_rdev_t *rdev, *freshest, *tmp;
char b[BDEVNAME_SIZE];
freshest = NULL;
@@ -3046,7 +3132,7 @@ action_store(mddev_t *mddev, const char *page, size_t len)
}
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
- sysfs_notify(&mddev->kobj, NULL, "sync_action");
+ sysfs_notify_dirent(mddev->sysfs_action);
return len;
}
@@ -3404,6 +3490,8 @@ md_attr_store(struct kobject *kobj, struct attribute *attr,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
rv = mddev_lock(mddev);
+ if (mddev->hold_active == UNTIL_IOCTL)
+ mddev->hold_active = 0;
if (!rv) {
rv = entry->store(mddev, page, length);
mddev_unlock(mddev);
@@ -3414,6 +3502,17 @@ md_attr_store(struct kobject *kobj, struct attribute *attr,
static void md_free(struct kobject *ko)
{
mddev_t *mddev = container_of(ko, mddev_t, kobj);
+
+ if (mddev->sysfs_state)
+ sysfs_put(mddev->sysfs_state);
+
+ if (mddev->gendisk) {
+ del_gendisk(mddev->gendisk);
+ put_disk(mddev->gendisk);
+ }
+ if (mddev->queue)
+ blk_cleanup_queue(mddev->queue);
+
kfree(mddev);
}
@@ -3429,34 +3528,74 @@ static struct kobj_type md_ktype = {
int mdp_major = 0;
-static struct kobject *md_probe(dev_t dev, int *part, void *data)
+static int md_alloc(dev_t dev, char *name)
{
static DEFINE_MUTEX(disks_mutex);
mddev_t *mddev = mddev_find(dev);
struct gendisk *disk;
- int partitioned = (MAJOR(dev) != MD_MAJOR);
- int shift = partitioned ? MdpMinorShift : 0;
- int unit = MINOR(dev) >> shift;
+ int partitioned;
+ int shift;
+ int unit;
int error;
if (!mddev)
- return NULL;
+ return -ENODEV;
+
+ partitioned = (MAJOR(mddev->unit) != MD_MAJOR);
+ shift = partitioned ? MdpMinorShift : 0;
+ unit = MINOR(mddev->unit) >> shift;
+
+ /* wait for any previous instance if this device
+ * to be completed removed (mddev_delayed_delete).
+ */
+ flush_scheduled_work();
mutex_lock(&disks_mutex);
if (mddev->gendisk) {
mutex_unlock(&disks_mutex);
mddev_put(mddev);
- return NULL;
+ return -EEXIST;
+ }
+
+ if (name) {
+ /* Need to ensure that 'name' is not a duplicate.
+ */
+ mddev_t *mddev2;
+ spin_lock(&all_mddevs_lock);
+
+ list_for_each_entry(mddev2, &all_mddevs, all_mddevs)
+ if (mddev2->gendisk &&
+ strcmp(mddev2->gendisk->disk_name, name) == 0) {
+ spin_unlock(&all_mddevs_lock);
+ return -EEXIST;
+ }
+ spin_unlock(&all_mddevs_lock);
+ }
+
+ mddev->queue = blk_alloc_queue(GFP_KERNEL);
+ if (!mddev->queue) {
+ mutex_unlock(&disks_mutex);
+ mddev_put(mddev);
+ return -ENOMEM;
}
+ /* Can be unlocked because the queue is new: no concurrency */
+ queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, mddev->queue);
+
+ blk_queue_make_request(mddev->queue, md_fail_request);
+
disk = alloc_disk(1 << shift);
if (!disk) {
mutex_unlock(&disks_mutex);
+ blk_cleanup_queue(mddev->queue);
+ mddev->queue = NULL;
mddev_put(mddev);
- return NULL;
+ return -ENOMEM;
}
- disk->major = MAJOR(dev);
+ disk->major = MAJOR(mddev->unit);
disk->first_minor = unit << shift;
- if (partitioned)
+ if (name)
+ strcpy(disk->disk_name, name);
+ else if (partitioned)
sprintf(disk->disk_name, "md_d%d", unit);
else
sprintf(disk->disk_name, "md%d", unit);
@@ -3464,7 +3603,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
disk->private_data = mddev;
disk->queue = mddev->queue;
/* Allow extended partitions. This makes the
- * 'mdp' device redundant, but we can really
+ * 'mdp' device redundant, but we can't really
* remove it now.
*/
disk->flags |= GENHD_FL_EXT_DEVT;
@@ -3480,9 +3619,35 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
kobject_uevent(&mddev->kobj, KOBJ_ADD);
mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, "array_state");
}
+ mddev_put(mddev);
+ return 0;
+}
+
+static struct kobject *md_probe(dev_t dev, int *part, void *data)
+{
+ md_alloc(dev, NULL);
return NULL;
}
+static int add_named_array(const char *val, struct kernel_param *kp)
+{
+ /* val must be "md_*" where * is not all digits.
+ * We allocate an array with a large free minor number, and
+ * set the name to val. val must not already be an active name.
+ */
+ int len = strlen(val);
+ char buf[DISK_NAME_LEN];
+
+ while (len && val[len-1] == '\n')
+ len--;
+ if (len >= DISK_NAME_LEN)
+ return -E2BIG;
+ strlcpy(buf, val, len+1);
+ if (strncmp(buf, "md_", 3) != 0)
+ return -EINVAL;
+ return md_alloc(0, buf);
+}
+
static void md_safemode_timeout(unsigned long data)
{
mddev_t *mddev = (mddev_t *) data;
@@ -3501,7 +3666,6 @@ static int do_md_run(mddev_t * mddev)
{
int err;
int chunk_size;
- struct list_head *tmp;
mdk_rdev_t *rdev;
struct gendisk *disk;
struct mdk_personality *pers;
@@ -3540,7 +3704,7 @@ static int do_md_run(mddev_t * mddev)
}
/* devices must have minimum size of one chunk */
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
if (test_bit(Faulty, &rdev->flags))
continue;
if (rdev->size < chunk_size / 1024) {
@@ -3565,7 +3729,7 @@ static int do_md_run(mddev_t * mddev)
* the only valid external interface is through the md
* device.
*/
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
if (test_bit(Faulty, &rdev->flags))
continue;
sync_blockdev(rdev->bdev);
@@ -3630,10 +3794,10 @@ static int do_md_run(mddev_t * mddev)
*/
char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
mdk_rdev_t *rdev2;
- struct list_head *tmp2;
int warned = 0;
- rdev_for_each(rdev, tmp, mddev) {
- rdev_for_each(rdev2, tmp2, mddev) {
+
+ list_for_each_entry(rdev, &mddev->disks, same_set)
+ list_for_each_entry(rdev2, &mddev->disks, same_set) {
if (rdev < rdev2 &&
rdev->bdev->bd_contains ==
rdev2->bdev->bd_contains) {
@@ -3647,7 +3811,7 @@ static int do_md_run(mddev_t * mddev)
warned = 1;
}
}
- }
+
if (warned)
printk(KERN_WARNING
"True protection against single-disk"
@@ -3684,6 +3848,7 @@ static int do_md_run(mddev_t * mddev)
printk(KERN_WARNING
"md: cannot register extra attributes for %s\n",
mdname(mddev));
+ mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action");
} else if (mddev->ro == 2) /* auto-readonly not meaningful */
mddev->ro = 0;
@@ -3694,7 +3859,7 @@ static int do_md_run(mddev_t * mddev)
mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */
mddev->in_sync = 1;
- rdev_for_each(rdev, tmp, mddev)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->raid_disk >= 0) {
char nm[20];
sprintf(nm, "rd%d", rdev->raid_disk);
@@ -3725,9 +3890,8 @@ static int do_md_run(mddev_t * mddev)
* it will remove the drives and not do the right thing
*/
if (mddev->degraded && !mddev->sync_thread) {
- struct list_head *rtmp;
int spares = 0;
- rdev_for_each(rdev, rtmp, mddev)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->raid_disk >= 0 &&
!test_bit(In_sync, &rdev->flags) &&
!test_bit(Faulty, &rdev->flags))
@@ -3754,7 +3918,8 @@ static int do_md_run(mddev_t * mddev)
mddev->changed = 1;
md_new_event(mddev);
sysfs_notify_dirent(mddev->sysfs_state);
- sysfs_notify(&mddev->kobj, NULL, "sync_action");
+ if (mddev->sysfs_action)
+ sysfs_notify_dirent(mddev->sysfs_action);
sysfs_notify(&mddev->kobj, NULL, "degraded");
kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
return 0;
@@ -3854,9 +4019,12 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
mddev->queue->merge_bvec_fn = NULL;
mddev->queue->unplug_fn = NULL;
mddev->queue->backing_dev_info.congested_fn = NULL;
- if (mddev->pers->sync_request)
+ if (mddev->pers->sync_request) {
sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
-
+ if (mddev->sysfs_action)
+ sysfs_put(mddev->sysfs_action);
+ mddev->sysfs_action = NULL;
+ }
module_put(mddev->pers->owner);
mddev->pers = NULL;
/* tell userspace to handle 'inactive' */
@@ -3883,7 +4051,6 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
*/
if (mode == 0) {
mdk_rdev_t *rdev;
- struct list_head *tmp;
printk(KERN_INFO "md: %s stopped.\n", mdname(mddev));
@@ -3895,7 +4062,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
}
mddev->bitmap_offset = 0;
- rdev_for_each(rdev, tmp, mddev)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->raid_disk >= 0) {
char nm[20];
sprintf(nm, "rd%d", rdev->raid_disk);
@@ -3941,6 +4108,8 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
mddev->barriers_work = 0;
mddev->safemode = 0;
kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
+ if (mddev->hold_active == UNTIL_STOP)
+ mddev->hold_active = 0;
} else if (mddev->pers)
printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -3956,7 +4125,6 @@ out:
static void autorun_array(mddev_t *mddev)
{
mdk_rdev_t *rdev;
- struct list_head *tmp;
int err;
if (list_empty(&mddev->disks))
@@ -3964,7 +4132,7 @@ static void autorun_array(mddev_t *mddev)
printk(KERN_INFO "md: running: ");
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
char b[BDEVNAME_SIZE];
printk("<%s>", bdevname(rdev->bdev,b));
}
@@ -3991,8 +4159,7 @@ static void autorun_array(mddev_t *mddev)
*/
static void autorun_devices(int part)
{
- struct list_head *tmp;
- mdk_rdev_t *rdev0, *rdev;
+ mdk_rdev_t *rdev0, *rdev, *tmp;
mddev_t *mddev;
char b[BDEVNAME_SIZE];
@@ -4007,7 +4174,7 @@ static void autorun_devices(int part)
printk(KERN_INFO "md: considering %s ...\n",
bdevname(rdev0->bdev,b));
INIT_LIST_HEAD(&candidates);
- rdev_for_each_list(rdev, tmp, pending_raid_disks)
+ rdev_for_each_list(rdev, tmp, &pending_raid_disks)
if (super_90_load(rdev, rdev0, 0) >= 0) {
printk(KERN_INFO "md: adding %s ...\n",
bdevname(rdev->bdev,b));
@@ -4053,7 +4220,7 @@ static void autorun_devices(int part)
} else {
printk(KERN_INFO "md: created %s\n", mdname(mddev));
mddev->persistent = 1;
- rdev_for_each_list(rdev, tmp, candidates) {
+ rdev_for_each_list(rdev, tmp, &candidates) {
list_del_init(&rdev->same_set);
if (bind_rdev_to_array(rdev, mddev))
export_rdev(rdev);
@@ -4064,7 +4231,7 @@ static void autorun_devices(int part)
/* on success, candidates will be empty, on error
* it won't...
*/
- rdev_for_each_list(rdev, tmp, candidates) {
+ rdev_for_each_list(rdev, tmp, &candidates) {
list_del_init(&rdev->same_set);
export_rdev(rdev);
}
@@ -4093,10 +4260,9 @@ static int get_array_info(mddev_t * mddev, void __user * arg)
mdu_array_info_t info;
int nr,working,active,failed,spare;
mdk_rdev_t *rdev;
- struct list_head *tmp;
nr=working=active=failed=spare=0;
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
nr++;
if (test_bit(Faulty, &rdev->flags))
failed++;
@@ -4614,9 +4780,8 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
static int update_size(mddev_t *mddev, sector_t num_sectors)
{
- mdk_rdev_t * rdev;
+ mdk_rdev_t *rdev;
int rv;
- struct list_head *tmp;
int fit = (num_sectors == 0);
if (mddev->pers->resize == NULL)
@@ -4638,7 +4803,7 @@ static int update_size(mddev_t *mddev, sector_t num_sectors)
* grow, and re-add.
*/
return -EBUSY;
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
sector_t avail;
avail = rdev->size * 2;
@@ -5000,6 +5165,9 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
done_unlock:
abort_unlock:
+ if (mddev->hold_active == UNTIL_IOCTL &&
+ err != -EINVAL)
+ mddev->hold_active = 0;
mddev_unlock(mddev);
return err;
@@ -5016,14 +5184,25 @@ static int md_open(struct block_device *bdev, fmode_t mode)
* Succeed if we can lock the mddev, which confirms that
* it isn't being stopped right now.
*/
- mddev_t *mddev = bdev->bd_disk->private_data;
+ mddev_t *mddev = mddev_find(bdev->bd_dev);
int err;
+ if (mddev->gendisk != bdev->bd_disk) {
+ /* we are racing with mddev_put which is discarding this
+ * bd_disk.
+ */
+ mddev_put(mddev);
+ /* Wait until bdev->bd_disk is definitely gone */
+ flush_scheduled_work();
+ /* Then retry the open from the top */
+ return -ERESTARTSYS;
+ }
+ BUG_ON(mddev != bdev->bd_disk->private_data);
+
if ((err = mutex_lock_interruptible_nested(&mddev->reconfig_mutex, 1)))
goto out;
err = 0;
- mddev_get(mddev);
atomic_inc(&mddev->openers);
mddev_unlock(mddev);
@@ -5187,11 +5366,10 @@ static void status_unused(struct seq_file *seq)
{
int i = 0;
mdk_rdev_t *rdev;
- struct list_head *tmp;
seq_printf(seq, "unused devices: ");
- rdev_for_each_list(rdev, tmp, pending_raid_disks) {
+ list_for_each_entry(rdev, &pending_raid_disks, same_set) {
char b[BDEVNAME_SIZE];
i++;
seq_printf(seq, "%s ",
@@ -5350,7 +5528,6 @@ static int md_seq_show(struct seq_file *seq, void *v)
{
mddev_t *mddev = v;
sector_t size;
- struct list_head *tmp2;
mdk_rdev_t *rdev;
struct mdstat_info *mi = seq->private;
struct bitmap *bitmap;
@@ -5387,7 +5564,7 @@ static int md_seq_show(struct seq_file *seq, void *v)
}
size = 0;
- rdev_for_each(rdev, tmp2, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
char b[BDEVNAME_SIZE];
seq_printf(seq, " %s[%d]",
bdevname(rdev->bdev,b), rdev->desc_nr);
@@ -5694,7 +5871,6 @@ void md_do_sync(mddev_t *mddev)
struct list_head *tmp;
sector_t last_check;
int skipped = 0;
- struct list_head *rtmp;
mdk_rdev_t *rdev;
char *desc;
@@ -5799,7 +5975,7 @@ void md_do_sync(mddev_t *mddev)
/* recovery follows the physical size of devices */
max_sectors = mddev->size << 1;
j = MaxSector;
- rdev_for_each(rdev, rtmp, mddev)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->raid_disk >= 0 &&
!test_bit(Faulty, &rdev->flags) &&
!test_bit(In_sync, &rdev->flags) &&
@@ -5949,7 +6125,7 @@ void md_do_sync(mddev_t *mddev)
} else {
if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
mddev->curr_resync = MaxSector;
- rdev_for_each(rdev, rtmp, mddev)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->raid_disk >= 0 &&
!test_bit(Faulty, &rdev->flags) &&
!test_bit(In_sync, &rdev->flags) &&
@@ -5985,10 +6161,9 @@ EXPORT_SYMBOL_GPL(md_do_sync);
static int remove_and_add_spares(mddev_t *mddev)
{
mdk_rdev_t *rdev;
- struct list_head *rtmp;
int spares = 0;
- rdev_for_each(rdev, rtmp, mddev)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->raid_disk >= 0 &&
!test_bit(Blocked, &rdev->flags) &&
(test_bit(Faulty, &rdev->flags) ||
@@ -6003,8 +6178,8 @@ static int remove_and_add_spares(mddev_t *mddev)
}
}
- if (mddev->degraded && ! mddev->ro) {
- rdev_for_each(rdev, rtmp, mddev) {
+ if (mddev->degraded && ! mddev->ro && !mddev->recovery_disabled) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
if (rdev->raid_disk >= 0 &&
!test_bit(In_sync, &rdev->flags) &&
!test_bit(Blocked, &rdev->flags))
@@ -6056,7 +6231,6 @@ static int remove_and_add_spares(mddev_t *mddev)
void md_check_recovery(mddev_t *mddev)
{
mdk_rdev_t *rdev;
- struct list_head *rtmp;
if (mddev->bitmap)
@@ -6120,7 +6294,7 @@ void md_check_recovery(mddev_t *mddev)
if (mddev->flags)
md_update_sb(mddev, 0);
- rdev_for_each(rdev, rtmp, mddev)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
if (test_and_clear_bit(StateChanged, &rdev->flags))
sysfs_notify_dirent(rdev->sysfs_state);
@@ -6149,13 +6323,13 @@ void md_check_recovery(mddev_t *mddev)
* information must be scrapped
*/
if (!mddev->degraded)
- rdev_for_each(rdev, rtmp, mddev)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
rdev->saved_raid_disk = -1;
mddev->recovery = 0;
/* flag recovery needed just to double check */
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
- sysfs_notify(&mddev->kobj, NULL, "sync_action");
+ sysfs_notify_dirent(mddev->sysfs_action);
md_new_event(mddev);
goto unlock;
}
@@ -6216,7 +6390,7 @@ void md_check_recovery(mddev_t *mddev)
mddev->recovery = 0;
} else
md_wakeup_thread(mddev->sync_thread);
- sysfs_notify(&mddev->kobj, NULL, "sync_action");
+ sysfs_notify_dirent(mddev->sysfs_action);
md_new_event(mddev);
}
unlock:
@@ -6224,7 +6398,8 @@ void md_check_recovery(mddev_t *mddev)
clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
if (test_and_clear_bit(MD_RECOVERY_RECOVER,
&mddev->recovery))
- sysfs_notify(&mddev->kobj, NULL, "sync_action");
+ if (mddev->sysfs_action)
+ sysfs_notify_dirent(mddev->sysfs_action);
}
mddev_unlock(mddev);
}
@@ -6386,14 +6561,8 @@ static __exit void md_exit(void)
unregister_sysctl_table(raid_table_header);
remove_proc_entry("mdstat", NULL);
for_each_mddev(mddev, tmp) {
- struct gendisk *disk = mddev->gendisk;
- if (!disk)
- continue;
export_array(mddev);
- del_gendisk(disk);
- put_disk(disk);
- mddev->gendisk = NULL;
- mddev_put(mddev);
+ mddev->hold_active = 0;
}
}
@@ -6418,6 +6587,7 @@ static int set_ro(const char *val, struct kernel_param *kp)
module_param_call(start_ro, set_ro, get_ro, NULL, S_IRUSR|S_IWUSR);
module_param(start_dirty_degraded, int, S_IRUGO|S_IWUSR);
+module_param_call(new_array, add_named_array, NULL, NULL, S_IWUSR);
EXPORT_SYMBOL(register_md_personality);
EXPORT_SYMBOL(unregister_md_personality);
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index d4ac47d11279..f6d08f241671 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -408,7 +408,6 @@ static int multipath_run (mddev_t *mddev)
int disk_idx;
struct multipath_info *disk;
mdk_rdev_t *rdev;
- struct list_head *tmp;
if (mddev->level != LEVEL_MULTIPATH) {
printk("multipath: %s: raid level not set to multipath IO (%d)\n",
@@ -441,7 +440,7 @@ static int multipath_run (mddev_t *mddev)
}
conf->working_disks = 0;
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
disk_idx = rdev->raid_disk;
if (disk_idx < 0 ||
disk_idx >= mddev->raid_disks)
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 8ac6488ad0dc..c605ba805586 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -53,11 +53,10 @@ static int raid0_congested(void *data, int bits)
static int create_strip_zones (mddev_t *mddev)
{
int i, c, j;
- sector_t current_offset, curr_zone_offset;
+ sector_t current_start, curr_zone_start;
sector_t min_spacing;
raid0_conf_t *conf = mddev_to_conf(mddev);
mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev;
- struct list_head *tmp1, *tmp2;
struct strip_zone *zone;
int cnt;
char b[BDEVNAME_SIZE];
@@ -67,19 +66,19 @@ static int create_strip_zones (mddev_t *mddev)
*/
conf->nr_strip_zones = 0;
- rdev_for_each(rdev1, tmp1, mddev) {
- printk("raid0: looking at %s\n",
+ list_for_each_entry(rdev1, &mddev->disks, same_set) {
+ printk(KERN_INFO "raid0: looking at %s\n",
bdevname(rdev1->bdev,b));
c = 0;
- rdev_for_each(rdev2, tmp2, mddev) {
- printk("raid0: comparing %s(%llu)",
+ list_for_each_entry(rdev2, &mddev->disks, same_set) {
+ printk(KERN_INFO "raid0: comparing %s(%llu)",
bdevname(rdev1->bdev,b),
(unsigned long long)rdev1->size);
- printk(" with %s(%llu)\n",
+ printk(KERN_INFO " with %s(%llu)\n",
bdevname(rdev2->bdev,b),
(unsigned long long)rdev2->size);
if (rdev2 == rdev1) {
- printk("raid0: END\n");
+ printk(KERN_INFO "raid0: END\n");
break;
}
if (rdev2->size == rdev1->size)
@@ -88,19 +87,20 @@ static int create_strip_zones (mddev_t *mddev)
* Not unique, don't count it as a new
* group
*/
- printk("raid0: EQUAL\n");
+ printk(KERN_INFO "raid0: EQUAL\n");
c = 1;
break;
}
- printk("raid0: NOT EQUAL\n");
+ printk(KERN_INFO "raid0: NOT EQUAL\n");
}
if (!c) {
- printk("raid0: ==> UNIQUE\n");
+ printk(KERN_INFO "raid0: ==> UNIQUE\n");
conf->nr_strip_zones++;
- printk("raid0: %d zones\n", conf->nr_strip_zones);
+ printk(KERN_INFO "raid0: %d zones\n",
+ conf->nr_strip_zones);
}
}
- printk("raid0: FINAL %d zones\n", conf->nr_strip_zones);
+ printk(KERN_INFO "raid0: FINAL %d zones\n", conf->nr_strip_zones);
conf->strip_zone = kzalloc(sizeof(struct strip_zone)*
conf->nr_strip_zones, GFP_KERNEL);
@@ -119,16 +119,17 @@ static int create_strip_zones (mddev_t *mddev)
cnt = 0;
smallest = NULL;
zone->dev = conf->devlist;
- rdev_for_each(rdev1, tmp1, mddev) {
+ list_for_each_entry(rdev1, &mddev->disks, same_set) {
int j = rdev1->raid_disk;
if (j < 0 || j >= mddev->raid_disks) {
- printk("raid0: bad disk number %d - aborting!\n", j);
+ printk(KERN_ERR "raid0: bad disk number %d - "
+ "aborting!\n", j);
goto abort;
}
if (zone->dev[j]) {
- printk("raid0: multiple devices for %d - aborting!\n",
- j);
+ printk(KERN_ERR "raid0: multiple devices for %d - "
+ "aborting!\n", j);
goto abort;
}
zone->dev[j] = rdev1;
@@ -149,16 +150,16 @@ static int create_strip_zones (mddev_t *mddev)
cnt++;
}
if (cnt != mddev->raid_disks) {
- printk("raid0: too few disks (%d of %d) - aborting!\n",
- cnt, mddev->raid_disks);
+ printk(KERN_ERR "raid0: too few disks (%d of %d) - "
+ "aborting!\n", cnt, mddev->raid_disks);
goto abort;
}
zone->nb_dev = cnt;
- zone->size = smallest->size * cnt;
- zone->zone_offset = 0;
+ zone->sectors = smallest->size * cnt * 2;
+ zone->zone_start = 0;
- current_offset = smallest->size;
- curr_zone_offset = zone->size;
+ current_start = smallest->size * 2;
+ curr_zone_start = zone->sectors;
/* now do the other zones */
for (i = 1; i < conf->nr_strip_zones; i++)
@@ -166,40 +167,41 @@ static int create_strip_zones (mddev_t *mddev)
zone = conf->strip_zone + i;
zone->dev = conf->strip_zone[i-1].dev + mddev->raid_disks;
- printk("raid0: zone %d\n", i);
- zone->dev_offset = current_offset;
+ printk(KERN_INFO "raid0: zone %d\n", i);
+ zone->dev_start = current_start;
smallest = NULL;
c = 0;
for (j=0; j<cnt; j++) {
char b[BDEVNAME_SIZE];
rdev = conf->strip_zone[0].dev[j];
- printk("raid0: checking %s ...", bdevname(rdev->bdev,b));
- if (rdev->size > current_offset)
- {
- printk(" contained as device %d\n", c);
+ printk(KERN_INFO "raid0: checking %s ...",
+ bdevname(rdev->bdev, b));
+ if (rdev->size > current_start / 2) {
+ printk(KERN_INFO " contained as device %d\n",
+ c);
zone->dev[c] = rdev;
c++;
if (!smallest || (rdev->size <smallest->size)) {
smallest = rdev;
- printk(" (%llu) is smallest!.\n",
+ printk(KERN_INFO " (%llu) is smallest!.\n",
(unsigned long long)rdev->size);
}
} else
- printk(" nope.\n");
+ printk(KERN_INFO " nope.\n");
}
zone->nb_dev = c;
- zone->size = (smallest->size - current_offset) * c;
- printk("raid0: zone->nb_dev: %d, size: %llu\n",
- zone->nb_dev, (unsigned long long)zone->size);
+ zone->sectors = (smallest->size * 2 - current_start) * c;
+ printk(KERN_INFO "raid0: zone->nb_dev: %d, sectors: %llu\n",
+ zone->nb_dev, (unsigned long long)zone->sectors);
- zone->zone_offset = curr_zone_offset;
- curr_zone_offset += zone->size;
+ zone->zone_start = curr_zone_start;
+ curr_zone_start += zone->sectors;
- current_offset = smallest->size;
- printk("raid0: current zone offset: %llu\n",
- (unsigned long long)current_offset);
+ current_start = smallest->size * 2;
+ printk(KERN_INFO "raid0: current zone start: %llu\n",
+ (unsigned long long)current_start);
}
/* Now find appropriate hash spacing.
@@ -210,16 +212,16 @@ static int create_strip_zones (mddev_t *mddev)
* strip though as it's size has no bearing on the efficacy of the hash
* table.
*/
- conf->hash_spacing = curr_zone_offset;
- min_spacing = curr_zone_offset;
+ conf->spacing = curr_zone_start;
+ min_spacing = curr_zone_start;
sector_div(min_spacing, PAGE_SIZE/sizeof(struct strip_zone*));
for (i=0; i < conf->nr_strip_zones-1; i++) {
- sector_t sz = 0;
- for (j=i; j<conf->nr_strip_zones-1 &&
- sz < min_spacing ; j++)
- sz += conf->strip_zone[j].size;
- if (sz >= min_spacing && sz < conf->hash_spacing)
- conf->hash_spacing = sz;
+ sector_t s = 0;
+ for (j = i; j < conf->nr_strip_zones - 1 &&
+ s < min_spacing; j++)
+ s += conf->strip_zone[j].sectors;
+ if (s >= min_spacing && s < conf->spacing)
+ conf->spacing = s;
}
mddev->queue->unplug_fn = raid0_unplug;
@@ -227,7 +229,7 @@ static int create_strip_zones (mddev_t *mddev)
mddev->queue->backing_dev_info.congested_fn = raid0_congested;
mddev->queue->backing_dev_info.congested_data = mddev;
- printk("raid0: done.\n");
+ printk(KERN_INFO "raid0: done.\n");
return 0;
abort:
return 1;
@@ -262,10 +264,9 @@ static int raid0_mergeable_bvec(struct request_queue *q,
static int raid0_run (mddev_t *mddev)
{
unsigned cur=0, i=0, nb_zone;
- s64 size;
+ s64 sectors;
raid0_conf_t *conf;
mdk_rdev_t *rdev;
- struct list_head *tmp;
if (mddev->chunk_size == 0) {
printk(KERN_ERR "md/raid0: non-zero chunk size required.\n");
@@ -291,54 +292,54 @@ static int raid0_run (mddev_t *mddev)
/* calculate array device size */
mddev->array_sectors = 0;
- rdev_for_each(rdev, tmp, mddev)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
mddev->array_sectors += rdev->size * 2;
- printk("raid0 : md_size is %llu blocks.\n",
- (unsigned long long)mddev->array_sectors / 2);
- printk("raid0 : conf->hash_spacing is %llu blocks.\n",
- (unsigned long long)conf->hash_spacing);
+ printk(KERN_INFO "raid0 : md_size is %llu sectors.\n",
+ (unsigned long long)mddev->array_sectors);
+ printk(KERN_INFO "raid0 : conf->spacing is %llu sectors.\n",
+ (unsigned long long)conf->spacing);
{
- sector_t s = mddev->array_sectors / 2;
- sector_t space = conf->hash_spacing;
+ sector_t s = mddev->array_sectors;
+ sector_t space = conf->spacing;
int round;
- conf->preshift = 0;
+ conf->sector_shift = 0;
if (sizeof(sector_t) > sizeof(u32)) {
/*shift down space and s so that sector_div will work */
while (space > (sector_t) (~(u32)0)) {
s >>= 1;
space >>= 1;
s += 1; /* force round-up */
- conf->preshift++;
+ conf->sector_shift++;
}
}
round = sector_div(s, (u32)space) ? 1 : 0;
nb_zone = s + round;
}
- printk("raid0 : nb_zone is %d.\n", nb_zone);
+ printk(KERN_INFO "raid0 : nb_zone is %d.\n", nb_zone);
- printk("raid0 : Allocating %Zd bytes for hash.\n",
+ printk(KERN_INFO "raid0 : Allocating %zu bytes for hash.\n",
nb_zone*sizeof(struct strip_zone*));
conf->hash_table = kmalloc (sizeof (struct strip_zone *)*nb_zone, GFP_KERNEL);
if (!conf->hash_table)
goto out_free_conf;
- size = conf->strip_zone[cur].size;
+ sectors = conf->strip_zone[cur].sectors;
conf->hash_table[0] = conf->strip_zone + cur;
for (i=1; i< nb_zone; i++) {
- while (size <= conf->hash_spacing) {
+ while (sectors <= conf->spacing) {
cur++;
- size += conf->strip_zone[cur].size;
+ sectors += conf->strip_zone[cur].sectors;
}
- size -= conf->hash_spacing;
+ sectors -= conf->spacing;
conf->hash_table[i] = conf->strip_zone + cur;
}
- if (conf->preshift) {
- conf->hash_spacing >>= conf->preshift;
- /* round hash_spacing up so when we divide by it, we
+ if (conf->sector_shift) {
+ conf->spacing >>= conf->sector_shift;
+ /* round spacing up so when we divide by it, we
* err on the side of too-low, which is safest
*/
- conf->hash_spacing++;
+ conf->spacing++;
}
/* calculate the max read-ahead size.
@@ -387,12 +388,12 @@ static int raid0_stop (mddev_t *mddev)
static int raid0_make_request (struct request_queue *q, struct bio *bio)
{
mddev_t *mddev = q->queuedata;
- unsigned int sect_in_chunk, chunksize_bits, chunk_size, chunk_sects;
+ unsigned int sect_in_chunk, chunksect_bits, chunk_sects;
raid0_conf_t *conf = mddev_to_conf(mddev);
struct strip_zone *zone;
mdk_rdev_t *tmp_dev;
sector_t chunk;
- sector_t block, rsect;
+ sector_t sector, rsect;
const int rw = bio_data_dir(bio);
int cpu;
@@ -407,11 +408,9 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio)
bio_sectors(bio));
part_stat_unlock();
- chunk_size = mddev->chunk_size >> 10;
chunk_sects = mddev->chunk_size >> 9;
- chunksize_bits = ffz(~chunk_size);
- block = bio->bi_sector >> 1;
-
+ chunksect_bits = ffz(~chunk_sects);
+ sector = bio->bi_sector;
if (unlikely(chunk_sects < (bio->bi_sector & (chunk_sects - 1)) + (bio->bi_size >> 9))) {
struct bio_pair *bp;
@@ -434,28 +433,27 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio)
{
- sector_t x = block >> conf->preshift;
- sector_div(x, (u32)conf->hash_spacing);
+ sector_t x = sector >> conf->sector_shift;
+ sector_div(x, (u32)conf->spacing);
zone = conf->hash_table[x];
}
-
- while (block >= (zone->zone_offset + zone->size))
+
+ while (sector >= zone->zone_start + zone->sectors)
zone++;
-
- sect_in_chunk = bio->bi_sector & ((chunk_size<<1) -1);
+
+ sect_in_chunk = bio->bi_sector & (chunk_sects - 1);
{
- sector_t x = (block - zone->zone_offset) >> chunksize_bits;
+ sector_t x = (sector - zone->zone_start) >> chunksect_bits;
sector_div(x, zone->nb_dev);
chunk = x;
- x = block >> chunksize_bits;
+ x = sector >> chunksect_bits;
tmp_dev = zone->dev[sector_div(x, zone->nb_dev)];
}
- rsect = (((chunk << chunksize_bits) + zone->dev_offset)<<1)
- + sect_in_chunk;
+ rsect = (chunk << chunksect_bits) + zone->dev_start + sect_in_chunk;
bio->bi_bdev = tmp_dev->bdev;
bio->bi_sector = rsect + tmp_dev->data_offset;
@@ -467,7 +465,7 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio)
bad_map:
printk("raid0_make_request bug: can't convert block across chunks"
- " or bigger than %dk %llu %d\n", chunk_size,
+ " or bigger than %dk %llu %d\n", chunk_sects / 2,
(unsigned long long)bio->bi_sector, bio->bi_size >> 10);
bio_io_error(bio);
@@ -492,10 +490,10 @@ static void raid0_status (struct seq_file *seq, mddev_t *mddev)
seq_printf(seq, "%s/", bdevname(
conf->strip_zone[j].dev[k]->bdev,b));
- seq_printf(seq, "] zo=%d do=%d s=%d\n",
- conf->strip_zone[j].zone_offset,
- conf->strip_zone[j].dev_offset,
- conf->strip_zone[j].size);
+ seq_printf(seq, "] zs=%d ds=%d s=%d\n",
+ conf->strip_zone[j].zone_start,
+ conf->strip_zone[j].dev_start,
+ conf->strip_zone[j].sectors);
}
#endif
seq_printf(seq, " %dk chunks", mddev->chunk_size/1024);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 9c788e2489b1..7b4f5f7155d8 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1016,12 +1016,16 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
* else mark the drive as failed
*/
if (test_bit(In_sync, &rdev->flags)
- && (conf->raid_disks - mddev->degraded) == 1)
+ && (conf->raid_disks - mddev->degraded) == 1) {
/*
* Don't fail the drive, act as though we were just a
- * normal single drive
+ * normal single drive.
+ * However don't try a recovery from this drive as
+ * it is very likely to fail.
*/
+ mddev->recovery_disabled = 1;
return;
+ }
if (test_and_clear_bit(In_sync, &rdev->flags)) {
unsigned long flags;
spin_lock_irqsave(&conf->device_lock, flags);
@@ -1919,7 +1923,6 @@ static int run(mddev_t *mddev)
int i, j, disk_idx;
mirror_info_t *disk;
mdk_rdev_t *rdev;
- struct list_head *tmp;
if (mddev->level != 1) {
printk("raid1: %s: raid level not set to mirroring (%d)\n",
@@ -1964,7 +1967,7 @@ static int run(mddev_t *mddev)
spin_lock_init(&conf->device_lock);
mddev->queue->queue_lock = &conf->device_lock;
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
disk_idx = rdev->raid_disk;
if (disk_idx >= mddev->raid_disks
|| disk_idx < 0)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 970a96ef9b18..6736d6dff981 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -2025,7 +2025,6 @@ static int run(mddev_t *mddev)
int i, disk_idx;
mirror_info_t *disk;
mdk_rdev_t *rdev;
- struct list_head *tmp;
int nc, fc, fo;
sector_t stride, size;
@@ -2108,7 +2107,7 @@ static int run(mddev_t *mddev)
spin_lock_init(&conf->device_lock);
mddev->queue->queue_lock = &conf->device_lock;
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
disk_idx = rdev->raid_disk;
if (disk_idx >= mddev->raid_disks
|| disk_idx < 0)
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index a36a7435edf5..a5ba080d303b 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3998,7 +3998,6 @@ static int run(mddev_t *mddev)
int raid_disk, memory;
mdk_rdev_t *rdev;
struct disk_info *disk;
- struct list_head *tmp;
int working_disks = 0;
if (mddev->level != 5 && mddev->level != 4 && mddev->level != 6) {
@@ -4108,7 +4107,7 @@ static int run(mddev_t *mddev)
pr_debug("raid5: run(%s) called.\n", mdname(mddev));
- rdev_for_each(rdev, tmp, mddev) {
+ list_for_each_entry(rdev, &mddev->disks, same_set) {
raid_disk = rdev->raid_disk;
if (raid_disk >= conf->raid_disks
|| raid_disk < 0)
@@ -4533,7 +4532,6 @@ static int raid5_start_reshape(mddev_t *mddev)
{
raid5_conf_t *conf = mddev_to_conf(mddev);
mdk_rdev_t *rdev;
- struct list_head *rtmp;
int spares = 0;
int added_devices = 0;
unsigned long flags;
@@ -4541,7 +4539,7 @@ static int raid5_start_reshape(mddev_t *mddev)
if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
return -EBUSY;
- rdev_for_each(rdev, rtmp, mddev)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->raid_disk < 0 &&
!test_bit(Faulty, &rdev->flags))
spares++;
@@ -4563,7 +4561,7 @@ static int raid5_start_reshape(mddev_t *mddev)
/* Add some new drives, as many as will fit.
* We know there are enough to make the newly sized array work.
*/
- rdev_for_each(rdev, rtmp, mddev)
+ list_for_each_entry(rdev, &mddev->disks, same_set)
if (rdev->raid_disk < 0 &&
!test_bit(Faulty, &rdev->flags)) {
if (raid5_add_disk(mddev, rdev) == 0) {
diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c
index 0ee79fd7c7a9..4b8662edb7cb 100644
--- a/drivers/media/common/tuners/tda8290.c
+++ b/drivers/media/common/tuners/tda8290.c
@@ -150,7 +150,7 @@ static void set_audio(struct dvb_frontend *fe,
}
}
-struct {
+static struct {
unsigned char seq[2];
} fm_mode[] = {
{ { 0x01, 0x81} }, /* Put device into expert mode */
@@ -207,7 +207,6 @@ static void tda8290_set_params(struct dvb_frontend *fe,
msleep(1);
if (params->mode == V4L2_TUNER_RADIO) {
- int i;
unsigned char deemphasis[] = { 0x13, 1 };
/* FIXME: allow using a different deemphasis */
@@ -767,7 +766,8 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
fe->ops.analog_ops.info.name = name;
if (priv->ver & TDA8290) {
- tda8290_init_tuner(fe);
+ if (priv->ver & (TDA8275 | TDA8275A))
+ tda8290_init_tuner(fe);
tda8290_init_if(fe);
} else if (priv->ver & TDA8295)
tda8295_init_if(fe);
diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig
index 1332301ef3ae..43f4d44edca6 100644
--- a/drivers/media/dvb/dm1105/Kconfig
+++ b/drivers/media/dvb/dm1105/Kconfig
@@ -1,6 +1,7 @@
config DVB_DM1105
tristate "SDMC DM1105 based PCI cards"
depends on DVB_CORE && PCI && I2C
+ depends on INPUT
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_STV0288 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 171f9ca124f7..843407785083 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -824,7 +824,7 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
return 0;
}
-struct dtv_cmds_h dtv_cmds[] = {
+static struct dtv_cmds_h dtv_cmds[] = {
[DTV_TUNE] = {
.name = "DTV_TUNE",
.cmd = DTV_TUNE,
@@ -962,7 +962,7 @@ struct dtv_cmds_h dtv_cmds[] = {
},
};
-void dtv_property_dump(struct dtv_property *tvp)
+static void dtv_property_dump(struct dtv_property *tvp)
{
int i;
@@ -993,7 +993,7 @@ void dtv_property_dump(struct dtv_property *tvp)
dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);
}
-int is_legacy_delivery_system(fe_delivery_system_t s)
+static int is_legacy_delivery_system(fe_delivery_system_t s)
{
if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) ||
(s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) ||
@@ -1007,7 +1007,8 @@ int is_legacy_delivery_system(fe_delivery_system_t s)
* drivers can use a single set_frontend tuning function, regardless of whether
* it's being used for the legacy or new API, reducing code and complexity.
*/
-void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+static void dtv_property_cache_sync(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -1059,7 +1060,7 @@ void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parame
/* Ensure the cached values are set correctly in the frontend
* legacy tuning structures, for the advanced tuning API.
*/
-void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
+static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
@@ -1114,7 +1115,7 @@ void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
/* Ensure the cached values are set correctly in the frontend
* legacy tuning structures, for the legacy tuning API.
*/
-void dtv_property_adv_params_sync(struct dvb_frontend *fe)
+static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
@@ -1149,7 +1150,7 @@ void dtv_property_adv_params_sync(struct dvb_frontend *fe)
}
}
-void dtv_property_cache_submit(struct dvb_frontend *fe)
+static void dtv_property_cache_submit(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
@@ -1180,8 +1181,9 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,
static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,
unsigned int cmd, void *parg);
-int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp,
- struct inode *inode, struct file *file)
+static int dtv_property_process_get(struct dvb_frontend *fe,
+ struct dtv_property *tvp,
+ struct inode *inode, struct file *file)
{
int r = 0;
@@ -1253,8 +1255,10 @@ int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp,
return r;
}
-int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,
- struct inode *inode, struct file *file)
+static int dtv_property_process_set(struct dvb_frontend *fe,
+ struct dtv_property *tvp,
+ struct inode *inode,
+ struct file *file)
{
int r = 0;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 03fd9dd5c685..f6ba8468858e 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -125,7 +125,6 @@ static void hexdump( const unsigned char *buf, unsigned short len )
struct dvb_net_priv {
int in_use;
- struct net_device_stats stats;
u16 pid;
struct net_device *net;
struct dvb_net *host;
@@ -384,8 +383,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_skb) {
dev_kfree_skb( priv->ule_skb );
/* Prepare for next SNDU. */
- priv->stats.rx_errors++;
- priv->stats.rx_frame_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_frame_errors++;
}
reset_ule(priv);
priv->need_pusi = 1;
@@ -438,8 +437,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
dev_kfree_skb( priv->ule_skb );
/* Prepare for next SNDU. */
// reset_ule(priv); moved to below.
- priv->stats.rx_errors++;
- priv->stats.rx_frame_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_frame_errors++;
}
reset_ule(priv);
/* skip to next PUSI. */
@@ -460,8 +459,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
/* Drop partly decoded SNDU, reset state, resync on PUSI. */
if (priv->ule_skb) {
dev_kfree_skb( priv->ule_skb );
- priv->stats.rx_errors++;
- priv->stats.rx_frame_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_frame_errors++;
}
reset_ule(priv);
priv->need_pusi = 1;
@@ -477,8 +476,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_sndu_remain > 183) {
/* Current SNDU lacks more data than there could be available in the
* current TS cell. */
- priv->stats.rx_errors++;
- priv->stats.rx_length_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "
"got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n",
priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);
@@ -520,8 +519,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_sndu_len < 5) {
printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. "
"Resyncing.\n", priv->ts_count, priv->ule_sndu_len);
- priv->stats.rx_errors++;
- priv->stats.rx_length_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_length_errors++;
priv->ule_sndu_len = 0;
priv->need_pusi = 1;
new_ts = 1;
@@ -573,7 +572,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_skb == NULL) {
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
dev->name);
- priv->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
@@ -637,8 +636,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
ule_dump = 1;
#endif
- priv->stats.rx_errors++;
- priv->stats.rx_crc_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_crc_errors++;
dev_kfree_skb(priv->ule_skb);
} else {
/* CRC32 verified OK. */
@@ -744,8 +743,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
* receive the packet anyhow. */
/* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
priv->ule_skb->pkt_type = PACKET_HOST; */
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += priv->ule_skb->len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += priv->ule_skb->len;
netif_rx(priv->ule_skb);
}
sndu_done:
@@ -800,8 +799,7 @@ static void dvb_net_sec(struct net_device *dev,
{
u8 *eth;
struct sk_buff *skb;
- struct net_device_stats *stats =
- &((struct dvb_net_priv *) netdev_priv(dev))->stats;
+ struct net_device_stats *stats = &dev->stats;
int snap = 0;
/* note: pkt_len includes a 32bit checksum */
@@ -1216,28 +1214,29 @@ static int dvb_net_stop(struct net_device *dev)
return dvb_net_feed_stop(dev);
}
-static struct net_device_stats * dvb_net_get_stats(struct net_device *dev)
-{
- return &((struct dvb_net_priv *) netdev_priv(dev))->stats;
-}
-
static const struct header_ops dvb_header_ops = {
.create = eth_header,
.parse = eth_header_parse,
.rebuild = eth_rebuild_header,
};
+
+static const struct net_device_ops dvb_netdev_ops = {
+ .ndo_open = dvb_net_open,
+ .ndo_stop = dvb_net_stop,
+ .ndo_start_xmit = dvb_net_tx,
+ .ndo_set_multicast_list = dvb_net_set_multicast_list,
+ .ndo_set_mac_address = dvb_net_set_mac,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
static void dvb_net_setup(struct net_device *dev)
{
ether_setup(dev);
dev->header_ops = &dvb_header_ops;
- dev->open = dvb_net_open;
- dev->stop = dvb_net_stop;
- dev->hard_start_xmit = dvb_net_tx;
- dev->get_stats = dvb_net_get_stats;
- dev->set_multicast_list = dvb_net_set_multicast_list;
- dev->set_mac_address = dvb_net_set_mac;
+ dev->netdev_ops = &dvb_netdev_ops;
dev->mtu = 4096;
dev->mc_count = 0;
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index 5017f08b14a6..c6e7b4215d6b 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -41,7 +41,7 @@
static int dvb_usb_anysee_debug;
module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-int dvb_usb_anysee_delsys;
+static int dvb_usb_anysee_delsys;
module_param_named(delsys, dvb_usb_anysee_delsys, int, 0644);
MODULE_PARM_DESC(delsys, "select delivery mode (0=DVB-C, 1=DVB-T)");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c
index 4f514d39b98f..28ad609e73f4 100644
--- a/drivers/media/dvb/frontends/cx24116.c
+++ b/drivers/media/dvb/frontends/cx24116.c
@@ -369,7 +369,7 @@ static int cx24116_set_inversion(struct cx24116_state *state,
* Not all S2 mmodulation schemes are support and not all rates with
* a scheme are support. Especially, no auto detect when in S2 mode.
*/
-struct cx24116_modfec {
+static struct cx24116_modfec {
fe_delivery_system_t delivery_system;
fe_modulation_t modulation;
fe_code_rate_t fec;
diff --git a/drivers/media/dvb/frontends/lgdt3304.c b/drivers/media/dvb/frontends/lgdt3304.c
index 469ace5692c6..3bb0c4394f8a 100644
--- a/drivers/media/dvb/frontends/lgdt3304.c
+++ b/drivers/media/dvb/frontends/lgdt3304.c
@@ -42,7 +42,7 @@ static int i2c_write_demod_bytes (struct dvb_frontend *fe, __u8 *buf, int len)
for (i=0; i<len-1; i+=3){
if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
- printk("%s i2c_transfer error %d\n", __FUNCTION__, err);
+ printk("%s i2c_transfer error %d\n", __func__, err);
if (err < 0)
return err;
else
@@ -73,7 +73,7 @@ static int lgdt3304_i2c_read_reg(struct dvb_frontend *fe, unsigned int reg)
i2cmsgs[1].buf = &buf;
if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) {
- printk("%s i2c_transfer error %d\n", __FUNCTION__, ret);
+ printk("%s i2c_transfer error %d\n", __func__, ret);
return ret;
}
@@ -94,7 +94,7 @@ static int lgdt3304_i2c_write_reg(struct dvb_frontend *fe, int reg, int val)
};
ret = i2c_transfer(state->i2c, &i2cmsgs, 1);
if (ret != 1) {
- printk("%s i2c_transfer error %d\n", __FUNCTION__, ret);
+ printk("%s i2c_transfer error %d\n", __func__, ret);
return ret;
}
@@ -238,7 +238,7 @@ static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_
}
if (err) {
- printk("%s error setting modulation\n", __FUNCTION__);
+ printk("%s error setting modulation\n", __func__);
} else {
state->current_modulation = param->u.vsb.modulation;
}
@@ -305,7 +305,7 @@ static int lgdt3304_read_status(struct dvb_frontend *fe, fe_status_t *status)
}
break;
default:
- printk("%s unhandled modulation\n", __FUNCTION__);
+ printk("%s unhandled modulation\n", __func__);
}
diff --git a/drivers/media/dvb/frontends/s921_module.c b/drivers/media/dvb/frontends/s921_module.c
index 3cbb9cb2cf47..892af8c9ed57 100644
--- a/drivers/media/dvb/frontends/s921_module.c
+++ b/drivers/media/dvb/frontends/s921_module.c
@@ -136,7 +136,7 @@ static int s921_write(void *dev, u8 reg, u8 val) {
};
if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
- printk("%s i2c_transfer error %d\n", __FUNCTION__, err);
+ printk("%s i2c_transfer error %d\n", __func__, err);
if (err < 0)
return err;
else
diff --git a/drivers/media/dvb/frontends/stb0899_algo.c b/drivers/media/dvb/frontends/stb0899_algo.c
index ced9b7ae7d50..83dc7e12d5f0 100644
--- a/drivers/media/dvb/frontends/stb0899_algo.c
+++ b/drivers/media/dvb/frontends/stb0899_algo.c
@@ -54,7 +54,7 @@ static u32 stb0899_calc_srate(u32 master_clk, u8 *sfr)
* stb0899_get_srate
* Get the current symbol rate
*/
-u32 stb0899_get_srate(struct stb0899_state *state)
+static u32 stb0899_get_srate(struct stb0899_state *state)
{
struct stb0899_internal *internal = &state->internal;
u8 sfr[3];
@@ -763,7 +763,7 @@ static void stb0899_dvbs2_config_csm_auto(struct stb0899_state *state)
stb0899_write_s2reg(state, STB0899_S2DEMOD, STB0899_BASE_CSM_CNTRL1, STB0899_OFF0_CSM_CNTRL1, reg);
}
-long Log2Int(int number)
+static long Log2Int(int number)
{
int i;
diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c
index bee28f77b93f..10613acf18f5 100644
--- a/drivers/media/dvb/frontends/stb0899_drv.c
+++ b/drivers/media/dvb/frontends/stb0899_drv.c
@@ -134,7 +134,7 @@ static const struct stb0899_tab stb0899_dvbs2rf_tab[] = {
};
/* DVB-S2 Es/N0 quant in dB/100 vs read value * 100*/
-struct stb0899_tab stb0899_quant_tab[] = {
+static struct stb0899_tab stb0899_quant_tab[] = {
{ 0, 0 },
{ 0, 100 },
{ 600, 200 },
@@ -177,7 +177,7 @@ struct stb0899_tab stb0899_quant_tab[] = {
};
/* DVB-S2 Es/N0 estimate in dB/100 vs read value */
-struct stb0899_tab stb0899_est_tab[] = {
+static struct stb0899_tab stb0899_est_tab[] = {
{ 0, 0 },
{ 0, 1 },
{ 301, 2 },
@@ -217,7 +217,7 @@ struct stb0899_tab stb0899_est_tab[] = {
{ 5721, 526017 },
};
-int _stb0899_read_reg(struct stb0899_state *state, unsigned int reg)
+static int _stb0899_read_reg(struct stb0899_state *state, unsigned int reg)
{
int ret;
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 3507463fdac9..bcbc5d41a0fe 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -1337,7 +1337,7 @@ static struct stb0899_config tt3200_config = {
.tuner_set_rfsiggain = NULL
};
-struct stb6100_config tt3200_stb6100_config = {
+static struct stb6100_config tt3200_stb6100_config = {
.tuner_address = 0x60,
.refclock = 27000000,
};
@@ -1450,7 +1450,7 @@ static void frontend_init(struct budget_ci *budget_ci)
if (budget_ci->budget.dvb_frontend) {
if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) {
if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
- printk("%s: No LNBP21 found!\n", __FUNCTION__);
+ printk("%s: No LNBP21 found!\n", __func__);
dvb_frontend_detach(budget_ci->budget.dvb_frontend);
budget_ci->budget.dvb_frontend = NULL;
}
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 34a39d2e4703..46fd573a4f15 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -569,7 +569,6 @@ static int cafe_smbus_setup(struct cafe_camera *cam)
cafe_smbus_enable_irq(cam);
adap->id = I2C_HW_SMBUS_CAFE;
- adap->class = I2C_CLASS_CAM_DIGITAL;
adap->owner = THIS_MODULE;
adap->client_register = cafe_smbus_attach;
adap->client_unregister = cafe_smbus_detach;
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index b0f837588e01..2d250a2a7bc3 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -69,6 +69,11 @@ config VIDEO_CX88_DVB
To compile this driver as a module, choose M here: the
module will be called cx88-dvb.
+config VIDEO_CX88_MPEG
+ tristate
+ depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD
+ default y
+
config VIDEO_CX88_VP3054
tristate "VP-3054 Secondary I2C Bus Support"
default m
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 6ec30f242578..b06b1275a9ec 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -3,7 +3,8 @@ cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \
cx8800-objs := cx88-video.o cx88-vbi.o
cx8802-objs := cx88-mpeg.o
-obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o
+obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o
+obj-$(CONFIG_VIDEO_CX88_MPEG) += cx8802.o
obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o
obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o
obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index da4dd4913d9f..613dfea4ff3e 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -138,6 +138,28 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
return ret;
}
+static void cx88_dvb_gate_ctrl(struct cx88_core *core, int open)
+{
+ struct videobuf_dvb_frontends *f;
+ struct videobuf_dvb_frontend *fe;
+
+ if (!core->dvbdev)
+ return;
+
+ f = &core->dvbdev->frontends;
+
+ if (!f)
+ return;
+
+ if (f->gate <= 1) /* undefined or fe0 */
+ fe = videobuf_dvb_get_frontend(f, 1);
+ else
+ fe = videobuf_dvb_get_frontend(f, f->gate);
+
+ if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
+ fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
+}
+
/* ------------------------------------------------------------------ */
static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
@@ -597,12 +619,30 @@ static int dvb_register(struct cx8802_dev *dev)
struct cx88_core *core = dev->core;
struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
int mfe_shared = 0; /* bus not shared by default */
+ int i;
if (0 != core->i2c_rc) {
printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name);
goto frontend_detach;
}
+ if (!core->board.num_frontends)
+ return -EINVAL;
+
+ mutex_init(&dev->frontends.lock);
+ INIT_LIST_HEAD(&dev->frontends.felist);
+
+ printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__,
+ core->board.num_frontends);
+ for (i = 1; i <= core->board.num_frontends; i++) {
+ fe0 = videobuf_dvb_alloc_frontend(&dev->frontends, i);
+ if (!fe0) {
+ printk(KERN_ERR "%s() failed to alloc\n", __func__);
+ videobuf_dvb_dealloc_frontends(&dev->frontends);
+ goto frontend_detach;
+ }
+ }
+
/* Get the first frontend */
fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
if (!fe0)
@@ -611,6 +651,9 @@ static int dvb_register(struct cx8802_dev *dev)
/* multi-frontend gate control is undefined or defaults to fe0 */
dev->frontends.gate = 0;
+ /* Sets the gate control callback to be used by i2c command calls */
+ core->gate_ctrl = cx88_dvb_gate_ctrl;
+
/* init frontend(s) */
switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_DVB_T1:
@@ -1109,6 +1152,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->pci->dev, adapter_nr, mfe_shared);
frontend_detach:
+ core->gate_ctrl = NULL;
videobuf_dvb_dealloc_frontends(&dev->frontends);
return -EINVAL;
}
@@ -1270,6 +1314,8 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
vp3054_i2c_remove(dev);
+ core->gate_ctrl = NULL;
+
return 0;
}
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 1ab691d20692..c0ff2305d804 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -116,30 +116,16 @@ static int detach_inform(struct i2c_client *client)
void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
{
-#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
- struct videobuf_dvb_frontends *f = &core->dvbdev->frontends;
- struct videobuf_dvb_frontend *fe = NULL;
-#endif
if (0 != core->i2c_rc)
return;
-#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
- if (core->dvbdev && f) {
- if(f->gate <= 1) /* undefined or fe0 */
- fe = videobuf_dvb_get_frontend(f, 1);
- else
- fe = videobuf_dvb_get_frontend(f, f->gate);
+ if (core->gate_ctrl)
+ core->gate_ctrl(core, 1);
- if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
- fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, 1);
+ i2c_clients_command(&core->i2c_adap, cmd, arg);
- i2c_clients_command(&core->i2c_adap, cmd, arg);
-
- if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
- fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, 0);
- } else
-#endif
- i2c_clients_command(&core->i2c_adap, cmd, arg);
+ if (core->gate_ctrl)
+ core->gate_ctrl(core, 0);
}
static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 59164fc94f5f..b295b76737e3 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -787,6 +787,9 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
dev->pci = pci_dev;
dev->core = core;
+ /* Maintain a reference so cx88-video can query the 8802 device. */
+ core->dvbdev = dev;
+
err = cx8802_init_common(dev);
if (err != 0)
goto fail_free;
@@ -794,32 +797,6 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
INIT_LIST_HEAD(&dev->drvlist);
list_add_tail(&dev->devlist,&cx8802_devlist);
-#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
- mutex_init(&dev->frontends.lock);
- INIT_LIST_HEAD(&dev->frontends.felist);
-
- if (core->board.num_frontends) {
- struct videobuf_dvb_frontend *fe;
- int i;
-
- printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__,
- core->board.num_frontends);
- for (i = 1; i <= core->board.num_frontends; i++) {
- fe = videobuf_dvb_alloc_frontend(&dev->frontends, i);
- if(fe == NULL) {
- printk(KERN_ERR "%s() failed to alloc\n",
- __func__);
- videobuf_dvb_dealloc_frontends(&dev->frontends);
- err = -ENOMEM;
- goto fail_free;
- }
- }
- }
-#endif
-
- /* Maintain a reference so cx88-video can query the 8802 device. */
- core->dvbdev = dev;
-
/* now autoload cx88-dvb or cx88-blackbird */
request_modules(dev);
return 0;
@@ -827,6 +804,7 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
fail_free:
kfree(dev);
fail_core:
+ core->dvbdev = NULL;
cx88_core_put(core,pci_dev);
return err;
}
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index eb9ce30dc5e6..60a8b3187f14 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -302,6 +302,7 @@ struct cx88_dmaqueue {
struct btcx_riscmem stopper;
u32 count;
};
+struct cx88_core;
struct cx88_core {
struct list_head devlist;
@@ -334,7 +335,8 @@ struct cx88_core {
/* config info -- dvb */
#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
- int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+ int (*prev_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+ void (*gate_ctrl)(struct cx88_core *core, int open);
#endif
/* state info */
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index e776699b62f9..ef9bf008a924 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -1842,7 +1842,7 @@ void em28xx_release_resources(struct em28xx *dev)
* em28xx_init_dev()
* allocates and inits the device structs, registers i2c bus and v4l device
*/
-int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
+static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
int minor)
{
struct em28xx *dev = *devhandle;
@@ -1990,8 +1990,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
int check_interface = 1;
isoc_pipe = 1;
endpoint = &interface->cur_altsetting->endpoint[1].desc;
- if (usb_endpoint_type(endpoint) !=
- USB_ENDPOINT_XFER_ISOC)
+ if (!usb_endpoint_xfer_isoc(endpoint))
check_interface = 0;
if (usb_endpoint_dir_out(endpoint))
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 819cceaa6ef4..eb5fb05fab22 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -393,7 +393,7 @@ static int em28xx_set_audio_source(struct em28xx *dev)
return ret;
}
-struct em28xx_vol_table outputs[] = {
+static const struct em28xx_vol_table outputs[] = {
{ EM28XX_AOUT_MASTER, AC97_MASTER_VOL },
{ EM28XX_AOUT_LINE, AC97_LINE_LEVEL_VOL },
{ EM28XX_AOUT_MONO, AC97_MASTER_MONO_VOL },
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 42bbaf64aceb..0443afe09ff8 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -307,7 +307,7 @@ static void em28xx_ir_work(struct work_struct *work)
mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
-void em28xx_ir_start(struct em28xx_IR *ir)
+static void em28xx_ir_start(struct em28xx_IR *ir)
{
setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
INIT_WORK(&ir->work, em28xx_ir_work);
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
index af3f2dc2c702..ccea4a758464 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
@@ -113,7 +113,7 @@ int s5k83a_power_down(struct sd *sd)
return 0;
}
-void s5k83a_dump_registers(struct sd *sd)
+static void s5k83a_dump_registers(struct sd *sd)
{
int address;
u8 page, old_page;
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index ca26b0c50cf2..05c14a29375a 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -1347,7 +1347,6 @@ static struct i2c_driver ov7670_driver = {
.name = "ov7670",
},
.id = I2C_DRIVERID_OV7670,
- .class = I2C_CLASS_CAM_DIGITAL,
.attach_adapter = ov7670_attach,
.detach_client = ov7670_detach,
.command = ov7670_command,
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
index 2c4acbf5a4fe..c841f4e4fbe4 100644
--- a/drivers/media/video/ovcamchip/ovcamchip_core.c
+++ b/drivers/media/video/ovcamchip/ovcamchip_core.c
@@ -405,7 +405,6 @@ static struct i2c_driver driver = {
.name = "ovcamchip",
},
.id = I2C_DRIVERID_OVCAMCHIP,
- .class = I2C_CLASS_CAM_DIGITAL,
.attach_adapter = ovcamchip_attach,
.detach_client = ovcamchip_detach,
.command = ovcamchip_command,
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 8fb92ac78c7b..fa304e5f252a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -3655,7 +3655,7 @@ void pvr2_hdw_device_reset(struct pvr2_hdw *hdw)
int ret;
pvr2_trace(PVR2_TRACE_INIT,"Performing a device reset...");
ret = usb_lock_device_for_reset(hdw->usb_dev,NULL);
- if (ret == 1) {
+ if (ret == 0) {
ret = usb_reset_device(hdw->usb_dev);
usb_unlock_device(hdw->usb_dev);
} else {
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 9d33de22cc48..a1d6008efcbb 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -34,12 +34,10 @@
#include <linux/videodev2.h>
-#include <asm/dma.h>
+#include <mach/dma.h>
#include <mach/pxa-regs.h>
#include <mach/camera.h>
-#include "pxa_camera.h"
-
#define PXA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
#define PXA_CAM_DRV_NAME "pxa27x-camera"
diff --git a/drivers/media/video/pxa_camera.h b/drivers/media/video/pxa_camera.h
deleted file mode 100644
index 89cbfc9a35c5..000000000000
--- a/drivers/media/video/pxa_camera.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* Camera Interface */
-#define CICR0 __REG(0x50000000)
-#define CICR1 __REG(0x50000004)
-#define CICR2 __REG(0x50000008)
-#define CICR3 __REG(0x5000000C)
-#define CICR4 __REG(0x50000010)
-#define CISR __REG(0x50000014)
-#define CIFR __REG(0x50000018)
-#define CITOR __REG(0x5000001C)
-#define CIBR0 __REG(0x50000028)
-#define CIBR1 __REG(0x50000030)
-#define CIBR2 __REG(0x50000038)
-
-#define CICR0_DMAEN (1 << 31) /* DMA request enable */
-#define CICR0_PAR_EN (1 << 30) /* Parity enable */
-#define CICR0_SL_CAP_EN (1 << 29) /* Capture enable for slave mode */
-#define CICR0_ENB (1 << 28) /* Camera interface enable */
-#define CICR0_DIS (1 << 27) /* Camera interface disable */
-#define CICR0_SIM (0x7 << 24) /* Sensor interface mode mask */
-#define CICR0_TOM (1 << 9) /* Time-out mask */
-#define CICR0_RDAVM (1 << 8) /* Receive-data-available mask */
-#define CICR0_FEM (1 << 7) /* FIFO-empty mask */
-#define CICR0_EOLM (1 << 6) /* End-of-line mask */
-#define CICR0_PERRM (1 << 5) /* Parity-error mask */
-#define CICR0_QDM (1 << 4) /* Quick-disable mask */
-#define CICR0_CDM (1 << 3) /* Disable-done mask */
-#define CICR0_SOFM (1 << 2) /* Start-of-frame mask */
-#define CICR0_EOFM (1 << 1) /* End-of-frame mask */
-#define CICR0_FOM (1 << 0) /* FIFO-overrun mask */
-
-#define CICR1_TBIT (1 << 31) /* Transparency bit */
-#define CICR1_RGBT_CONV (0x3 << 29) /* RGBT conversion mask */
-#define CICR1_PPL (0x7ff << 15) /* Pixels per line mask */
-#define CICR1_RGB_CONV (0x7 << 12) /* RGB conversion mask */
-#define CICR1_RGB_F (1 << 11) /* RGB format */
-#define CICR1_YCBCR_F (1 << 10) /* YCbCr format */
-#define CICR1_RGB_BPP (0x7 << 7) /* RGB bis per pixel mask */
-#define CICR1_RAW_BPP (0x3 << 5) /* Raw bis per pixel mask */
-#define CICR1_COLOR_SP (0x3 << 3) /* Color space mask */
-#define CICR1_DW (0x7 << 0) /* Data width mask */
-
-#define CICR2_BLW (0xff << 24) /* Beginning-of-line pixel clock
- wait count mask */
-#define CICR2_ELW (0xff << 16) /* End-of-line pixel clock
- wait count mask */
-#define CICR2_HSW (0x3f << 10) /* Horizontal sync pulse width mask */
-#define CICR2_BFPW (0x3f << 3) /* Beginning-of-frame pixel clock
- wait count mask */
-#define CICR2_FSW (0x7 << 0) /* Frame stabilization
- wait count mask */
-
-#define CICR3_BFW (0xff << 24) /* Beginning-of-frame line clock
- wait count mask */
-#define CICR3_EFW (0xff << 16) /* End-of-frame line clock
- wait count mask */
-#define CICR3_VSW (0x3f << 10) /* Vertical sync pulse width mask */
-#define CICR3_BFPW (0x3f << 3) /* Beginning-of-frame pixel clock
- wait count mask */
-#define CICR3_LPF (0x7ff << 0) /* Lines per frame mask */
-
-#define CICR4_MCLK_DLY (0x3 << 24) /* MCLK Data Capture Delay mask */
-#define CICR4_PCLK_EN (1 << 23) /* Pixel clock enable */
-#define CICR4_PCP (1 << 22) /* Pixel clock polarity */
-#define CICR4_HSP (1 << 21) /* Horizontal sync polarity */
-#define CICR4_VSP (1 << 20) /* Vertical sync polarity */
-#define CICR4_MCLK_EN (1 << 19) /* MCLK enable */
-#define CICR4_FR_RATE (0x7 << 8) /* Frame rate mask */
-#define CICR4_DIV (0xff << 0) /* Clock divisor mask */
-
-#define CISR_FTO (1 << 15) /* FIFO time-out */
-#define CISR_RDAV_2 (1 << 14) /* Channel 2 receive data available */
-#define CISR_RDAV_1 (1 << 13) /* Channel 1 receive data available */
-#define CISR_RDAV_0 (1 << 12) /* Channel 0 receive data available */
-#define CISR_FEMPTY_2 (1 << 11) /* Channel 2 FIFO empty */
-#define CISR_FEMPTY_1 (1 << 10) /* Channel 1 FIFO empty */
-#define CISR_FEMPTY_0 (1 << 9) /* Channel 0 FIFO empty */
-#define CISR_EOL (1 << 8) /* End of line */
-#define CISR_PAR_ERR (1 << 7) /* Parity error */
-#define CISR_CQD (1 << 6) /* Camera interface quick disable */
-#define CISR_CDD (1 << 5) /* Camera interface disable done */
-#define CISR_SOF (1 << 4) /* Start of frame */
-#define CISR_EOF (1 << 3) /* End of frame */
-#define CISR_IFO_2 (1 << 2) /* FIFO overrun for Channel 2 */
-#define CISR_IFO_1 (1 << 1) /* FIFO overrun for Channel 1 */
-#define CISR_IFO_0 (1 << 0) /* FIFO overrun for Channel 0 */
-
-#define CIFR_FLVL2 (0x7f << 23) /* FIFO 2 level mask */
-#define CIFR_FLVL1 (0x7f << 16) /* FIFO 1 level mask */
-#define CIFR_FLVL0 (0xff << 8) /* FIFO 0 level mask */
-#define CIFR_THL_0 (0x3 << 4) /* Threshold Level for Channel 0 FIFO */
-#define CIFR_RESET_F (1 << 3) /* Reset input FIFOs */
-#define CIFR_FEN2 (1 << 2) /* FIFO enable for channel 2 */
-#define CIFR_FEN1 (1 << 1) /* FIFO enable for channel 1 */
-#define CIFR_FEN0 (1 << 0) /* FIFO enable for channel 0 */
-
diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c
index f8d85ddb4804..b08549661781 100644
--- a/drivers/media/video/usbvideo/ibmcam.c
+++ b/drivers/media/video/usbvideo/ibmcam.c
@@ -3779,7 +3779,7 @@ static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *
err("Alternate settings have different endpoint addresses!");
return -ENODEV;
}
- if (usb_endpoint_type(endpoint) != USB_ENDPOINT_XFER_ISOC) {
+ if (!usb_endpoint_xfer_isoc(endpoint)) {
err("Interface %d. has non-ISO endpoint!", ifnum);
return -ENODEV;
}
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index 90f0ce6a26bc..900ec2129ca1 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -823,7 +823,7 @@ static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id
err("Alternate settings have different endpoint addresses!");
return -ENODEV;
}
- if (usb_endpoint_type(endpoint) != USB_ENDPOINT_XFER_ISOC) {
+ if (!usb_endpoint_xfer_isoc(endpoint)) {
err("Interface %d. has non-ISO endpoint!",
interface->desc.bInterfaceNumber);
return -ENODEV;
diff --git a/drivers/media/video/usbvideo/ultracam.c b/drivers/media/video/usbvideo/ultracam.c
index 839a08240c25..fbd1b6392290 100644
--- a/drivers/media/video/usbvideo/ultracam.c
+++ b/drivers/media/video/usbvideo/ultracam.c
@@ -556,7 +556,7 @@ static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id
err("Alternate settings have different endpoint addresses!");
return -ENODEV;
}
- if (usb_endpoint_type(endpoint) != USB_ENDPOINT_XFER_ISOC) {
+ if (!usb_endpoint_xfer_isoc(endpoint)) {
err("Interface %d. has non-ISO endpoint!",
interface->desc.bInterfaceNumber);
return -ENODEV;
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 2be5e47ed081..2622de003a45 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -1674,8 +1674,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
interface = &dev->actconfig->interface[ifnum]->altsetting[0];
}
endpoint = &interface->endpoint[1].desc;
- if (usb_endpoint_type(endpoint) !=
- USB_ENDPOINT_XFER_ISOC) {
+ if (!usb_endpoint_xfer_isoc(endpoint)) {
err("%s: interface %d. has non-ISO endpoint!",
__func__, ifnum);
err("%s: Endpoint attributes %d",
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index 9eefde031597..cf9d4c7f571a 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -29,7 +29,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
if (dev == NULL || v4l2_dev == NULL)
return -EINVAL;
/* Warn if we apparently re-register a device */
- WARN_ON(dev_get_drvdata(dev));
+ WARN_ON(dev_get_drvdata(dev) != NULL);
INIT_LIST_HEAD(&v4l2_dev->subdevs);
spin_lock_init(&v4l2_dev->lock);
v4l2_dev->dev = dev;
@@ -61,7 +61,7 @@ int v4l2_device_register_subdev(struct v4l2_device *dev, struct v4l2_subdev *sd)
if (dev == NULL || sd == NULL || !sd->name[0])
return -EINVAL;
/* Warn if we apparently re-register a subdev */
- WARN_ON(sd->dev);
+ WARN_ON(sd->dev != NULL);
if (!try_module_get(sd->owner))
return -ENODEV;
sd->dev = dev;
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index bc6d5aba0fe6..da1790e57a86 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -388,8 +388,7 @@ videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
page = alloc_page(GFP_USER | __GFP_DMA32);
if (!page)
return VM_FAULT_OOM;
- clear_user_page(page_address(page), (unsigned long)vmf->virtual_address,
- page);
+ clear_user_highpage(page, (unsigned long)vmf->virtual_address);
vmf->page = page;
return 0;
}
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index a3997b7d4366..105a832531f2 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -1553,7 +1553,6 @@ static int w9968cf_i2c_init(struct w9968cf_device* cam)
static struct i2c_adapter adap = {
.id = I2C_HW_SMBUS_W9968CF,
- .class = I2C_CLASS_CAM_DIGITAL,
.owner = THIS_MODULE,
.client_register = w9968cf_i2c_attach_inform,
.client_unregister = w9968cf_i2c_detach_inform,
diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c
index 1f1e3982b1aa..de143deb06f0 100644
--- a/drivers/memstick/core/mspro_block.c
+++ b/drivers/memstick/core/mspro_block.c
@@ -52,14 +52,14 @@ struct mspro_sys_attr {
};
struct mspro_attr_entry {
- unsigned int address;
- unsigned int size;
+ __be32 address;
+ __be32 size;
unsigned char id;
unsigned char reserved[3];
} __attribute__((packed));
struct mspro_attribute {
- unsigned short signature;
+ __be16 signature;
unsigned short version;
unsigned char count;
unsigned char reserved[11];
@@ -69,28 +69,28 @@ struct mspro_attribute {
struct mspro_sys_info {
unsigned char class;
unsigned char reserved0;
- unsigned short block_size;
- unsigned short block_count;
- unsigned short user_block_count;
- unsigned short page_size;
+ __be16 block_size;
+ __be16 block_count;
+ __be16 user_block_count;
+ __be16 page_size;
unsigned char reserved1[2];
unsigned char assembly_date[8];
- unsigned int serial_number;
+ __be32 serial_number;
unsigned char assembly_maker_code;
unsigned char assembly_model_code[3];
- unsigned short memory_maker_code;
- unsigned short memory_model_code;
+ __be16 memory_maker_code;
+ __be16 memory_model_code;
unsigned char reserved2[4];
unsigned char vcc;
unsigned char vpp;
- unsigned short controller_number;
- unsigned short controller_function;
- unsigned short start_sector;
- unsigned short unit_size;
+ __be16 controller_number;
+ __be16 controller_function;
+ __be16 start_sector;
+ __be16 unit_size;
unsigned char ms_sub_class;
unsigned char reserved3[4];
unsigned char interface_type;
- unsigned short controller_code;
+ __be16 controller_code;
unsigned char format_type;
unsigned char reserved4;
unsigned char device_type;
@@ -124,11 +124,11 @@ struct mspro_specfile {
} __attribute__((packed));
struct mspro_devinfo {
- unsigned short cylinders;
- unsigned short heads;
- unsigned short bytes_per_track;
- unsigned short bytes_per_sector;
- unsigned short sectors_per_track;
+ __be16 cylinders;
+ __be16 heads;
+ __be16 bytes_per_track;
+ __be16 bytes_per_sector;
+ __be16 sectors_per_track;
unsigned char reserved[6];
} __attribute__((packed));
@@ -338,8 +338,7 @@ static ssize_t mspro_block_attr_show_sysinfo(struct device *dev,
rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: "
"GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n",
date_tz, date_tz_f,
- be16_to_cpu(*(unsigned short *)
- &x_sys->assembly_date[1]),
+ be16_to_cpup((__be16 *)&x_sys->assembly_date[1]),
x_sys->assembly_date[3], x_sys->assembly_date[4],
x_sys->assembly_date[5], x_sys->assembly_date[6],
x_sys->assembly_date[7]);
diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h
index 10b6ef758725..11c0f461320e 100644
--- a/drivers/message/fusion/lsi/mpi.h
+++ b/drivers/message/fusion/lsi/mpi.h
@@ -6,7 +6,7 @@
* Title: MPI Message independent structures and definitions
* Creation Date: July 27, 2000
*
- * mpi.h Version: 01.05.13
+ * mpi.h Version: 01.05.16
*
* Version History
* ---------------
@@ -79,6 +79,9 @@
* 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT.
* 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT.
* 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT.
+ * 08-07-07 01.05.14 Bumped MPI_HEADER_VERSION_UNIT.
+ * 01-15-08 01.05.15 Bumped MPI_HEADER_VERSION_UNIT.
+ * 03-28-08 01.05.16 Bumped MPI_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -109,7 +112,7 @@
/* Note: The major versions of 0xe0 through 0xff are reserved */
/* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT (0x10)
+#define MPI_HEADER_VERSION_UNIT (0x13)
#define MPI_HEADER_VERSION_DEV (0x00)
#define MPI_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI_HEADER_VERSION_UNIT_SHIFT (8)
diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
index b2db3330c591..013c7d881948 100644
--- a/drivers/message/fusion/lsi/mpi_cnfg.h
+++ b/drivers/message/fusion/lsi/mpi_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Config message, structures, and Pages
* Creation Date: July 27, 2000
*
- * mpi_cnfg.h Version: 01.05.15
+ * mpi_cnfg.h Version: 01.05.18
*
* Version History
* ---------------
@@ -308,6 +308,20 @@
* Expander Page 0 Flags field.
* Fixed define for
* MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED.
+ * 08-07-07 01.05.16 Added MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT
+ * define.
+ * Added BIOS Page 4 structure.
+ * Added MPI_RAID_PHYS_DISK1_PATH_MAX define for RAID
+ * Physcial Disk Page 1.
+ * 01-15-07 01.05.17 Added additional bit defines for ExtFlags field of
+ * Manufacturing Page 4.
+ * Added Solid State Drives Supported bit to IOC Page 6
+ * Capabilities Flags.
+ * Added new value for AccessStatus field of SAS Device
+ * Page 0 (_SATA_NEEDS_INITIALIZATION).
+ * 03-28-08 01.05.18 Defined new bits in Manufacturing Page 4 ExtFlags field
+ * to control coercion size and the mixing of SAS and SATA
+ * SSD drives.
* --------------------------------------------------------------------------
*/
@@ -686,6 +700,14 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_4
#define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01)
/* defines for the ExtFlags field */
+#define MPI_MANPAGE4_EXTFLAGS_MASK_COERCION_SIZE (0x0180)
+#define MPI_MANPAGE4_EXTFLAGS_SHIFT_COERCION_SIZE (7)
+#define MPI_MANPAGE4_EXTFLAGS_1GB_COERCION_SIZE (0)
+#define MPI_MANPAGE4_EXTFLAGS_128MB_COERCION_SIZE (1)
+
+#define MPI_MANPAGE4_EXTFLAGS_NO_MIX_SSD_SAS_SATA (0x0040)
+#define MPI_MANPAGE4_EXTFLAGS_MIX_SSD_AND_NON_SSD (0x0020)
+#define MPI_MANPAGE4_EXTFLAGS_DUAL_PORT_SUPPORT (0x0010)
#define MPI_MANPAGE4_EXTFLAGS_HIDE_NON_IR_METADATA (0x0008)
#define MPI_MANPAGE4_EXTFLAGS_SAS_CACHE_DISABLE (0x0004)
#define MPI_MANPAGE4_EXTFLAGS_SATA_CACHE_DISABLE (0x0002)
@@ -1159,6 +1181,8 @@ typedef struct _CONFIG_PAGE_IOC_6
/* IOC Page 6 Capabilities Flags */
+#define MPI_IOCPAGE6_CAP_FLAGS_SSD_SUPPORT (0x00000020)
+#define MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT (0x00000010)
#define MPI_IOCPAGE6_CAP_FLAGS_DISABLE_SMART_POLLING (0x00000008)
#define MPI_IOCPAGE6_CAP_FLAGS_MASK_METADATA_SIZE (0x00000006)
@@ -1428,6 +1452,15 @@ typedef struct _CONFIG_PAGE_BIOS_2
#define MPI_BIOSPAGE2_FORM_SAS_WWN (0x05)
#define MPI_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06)
+typedef struct _CONFIG_PAGE_BIOS_4
+{
+ CONFIG_PAGE_HEADER Header; /* 00h */
+ U64 ReassignmentBaseWWID; /* 04h */
+} CONFIG_PAGE_BIOS_4, MPI_POINTER PTR_CONFIG_PAGE_BIOS_4,
+ BIOSPage4_t, MPI_POINTER pBIOSPage4_t;
+
+#define MPI_BIOSPAGE4_PAGEVERSION (0x00)
+
/****************************************************************************
* SCSI Port Config Pages
@@ -2419,6 +2452,15 @@ typedef struct _RAID_PHYS_DISK1_PATH
#define MPI_RAID_PHYSDISK1_FLAG_BROKEN (0x0002)
#define MPI_RAID_PHYSDISK1_FLAG_INVALID (0x0001)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength or NumPhysDiskPaths at runtime.
+ */
+#ifndef MPI_RAID_PHYS_DISK1_PATH_MAX
+#define MPI_RAID_PHYS_DISK1_PATH_MAX (1)
+#endif
+
typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_1
{
CONFIG_PAGE_HEADER Header; /* 00h */
@@ -2426,7 +2468,7 @@ typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_1
U8 PhysDiskNum; /* 05h */
U16 Reserved2; /* 06h */
U32 Reserved1; /* 08h */
- RAID_PHYS_DISK1_PATH Path[1]; /* 0Ch */
+ RAID_PHYS_DISK1_PATH Path[MPI_RAID_PHYS_DISK1_PATH_MAX];/* 0Ch */
} CONFIG_PAGE_RAID_PHYS_DISK_1, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_1,
RaidPhysDiskPage1_t, MPI_POINTER pRaidPhysDiskPage1_t;
@@ -2844,6 +2886,7 @@ typedef struct _CONFIG_PAGE_SAS_DEVICE_0
#define MPI_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01)
#define MPI_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02)
#define MPI_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03)
+#define MPI_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04)
/* specific values for SATA Init failures */
#define MPI_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10)
#define MPI_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11)
diff --git a/drivers/message/fusion/lsi/mpi_fc.h b/drivers/message/fusion/lsi/mpi_fc.h
index 627acfbb8623..7d663ce76f8c 100644
--- a/drivers/message/fusion/lsi/mpi_fc.h
+++ b/drivers/message/fusion/lsi/mpi_fc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 LSI Corporation.
+ * Copyright (c) 2000-2008 LSI Corporation.
*
*
* Name: mpi_fc.h
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt
index 3f15fcfe4a2e..693e4b511354 100644
--- a/drivers/message/fusion/lsi/mpi_history.txt
+++ b/drivers/message/fusion/lsi/mpi_history.txt
@@ -3,28 +3,28 @@
MPI Header File Change History
==============================
- Copyright (c) 2000-2007 LSI Corporation.
+ Copyright (c) 2000-2008 LSI Corporation.
---------------------------------------
- Header Set Release Version: 01.05.16
- Header Set Release Date: 05-24-07
+ Header Set Release Version: 01.05.19
+ Header Set Release Date: 03-28-08
---------------------------------------
Filename Current version Prior version
---------- --------------- -------------
- mpi.h 01.05.13 01.05.12
- mpi_ioc.h 01.05.14 01.05.13
- mpi_cnfg.h 01.05.15 01.05.14
+ mpi.h 01.05.16 01.05.15
+ mpi_ioc.h 01.05.16 01.05.15
+ mpi_cnfg.h 01.05.18 01.05.17
mpi_init.h 01.05.09 01.05.09
mpi_targ.h 01.05.06 01.05.06
mpi_fc.h 01.05.01 01.05.01
mpi_lan.h 01.05.01 01.05.01
- mpi_raid.h 01.05.03 01.05.03
+ mpi_raid.h 01.05.05 01.05.05
mpi_tool.h 01.05.03 01.05.03
mpi_inb.h 01.05.01 01.05.01
- mpi_sas.h 01.05.04 01.05.04
+ mpi_sas.h 01.05.05 01.05.05
mpi_type.h 01.05.02 01.05.02
- mpi_history.txt 01.05.14 01.05.14
+ mpi_history.txt 01.05.19 01.05.18
* Date Version Description
@@ -96,6 +96,9 @@ mpi.h
* 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT.
* 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT.
* 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT.
+ * 08-07-07 01.05.14 Bumped MPI_HEADER_VERSION_UNIT.
+ * 01-15-08 01.05.15 Bumped MPI_HEADER_VERSION_UNIT.
+ * 03-28-08 01.05.16 Bumped MPI_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
mpi_ioc.h
@@ -127,7 +130,7 @@ mpi_ioc.h
* 08-08-01 01.02.01 Original release for v1.2 work.
* New format for FWVersion and ProductId in
* MSG_IOC_FACTS_REPLY and MPI_FW_HEADER.
- * 08-31-01 01.02.02 Added event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and
+ * 08-31-01 01.02.02 Addded event MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE and
* related structure and defines.
* Added event MPI_EVENT_ON_BUS_TIMER_EXPIRED.
* Added MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE.
@@ -187,7 +190,7 @@ mpi_ioc.h
* 10-11-06 01.05.12 Added MPI_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED.
* Added MaxInitiators field to PortFacts reply.
* Added SAS Device Status Change ReasonCode for
- * asynchronous notification.
+ * asynchronous notificaiton.
* Added MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE and event
* data structure.
* Added new ImageType values for FWDownload and FWUpload
@@ -199,6 +202,16 @@ mpi_ioc.h
* added _MULTI_PORT_DOMAIN.
* 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request.
* Added Common Boot Block type to FWUpload Request.
+ * 08-07-07 01.05.15 Added MPI_EVENT_SAS_INIT_RC_REMOVED define.
+ * Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and
+ * MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data.
+ * Added SASAddress field to SAS Initiator Device Table
+ * Overflow event data structure.
+ * 03-28-08 01.05.16 Added two new ReasonCode values to SAS Device Status
+ * Change Event data to indicate completion of internally
+ * generated task management.
+ * Added MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE define.
+ * Added MPI_EVENT_SAS_INIT_RC_INACCESSIBLE define.
* --------------------------------------------------------------------------
mpi_cnfg.h
@@ -213,7 +226,7 @@ mpi_cnfg.h
* Added _RESPONSE_ID_MASK definition to SCSI_PORT_1
* page and updated the page version.
* Added Information field and _INFO_PARAMS_NEGOTIATED
- * definition to SCSI_DEVICE_0 page.
+ * definitionto SCSI_DEVICE_0 page.
* 06-22-00 01.00.03 Removed batch controls from LAN_0 page and updated the
* page version.
* Added BucketsRemaining to LAN_1 page, redefined the
@@ -496,6 +509,20 @@ mpi_cnfg.h
* Expander Page 0 Flags field.
* Fixed define for
* MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED.
+ * 08-07-07 01.05.16 Added MPI_IOCPAGE6_CAP_FLAGS_MULTIPORT_DRIVE_SUPPORT
+ * define.
+ * Added BIOS Page 4 structure.
+ * Added MPI_RAID_PHYS_DISK1_PATH_MAX define for RAID
+ * Physcial Disk Page 1.
+ * 01-15-07 01.05.17 Added additional bit defines for ExtFlags field of
+ * Manufacturing Page 4.
+ * Added Solid State Drives Supported bit to IOC Page 6
+ * Capabilities Flags.
+ * Added new value for AccessStatus field of SAS Device
+ * Page 0 (_SATA_NEEDS_INITIALIZATION).
+ * 03-28-08 01.05.18 Defined new bits in Manufacturing Page 4 ExtFlags field
+ * to control coercion size and the mixing of SAS and SATA
+ * SSD drives.
* --------------------------------------------------------------------------
mpi_init.h
@@ -661,6 +688,9 @@ mpi_raid.h
* _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE.
* 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and
* associated defines.
+ * 08-07-07 01.05.04 Added Disable Full Rebuild bit to the ActionDataWord
+ * for the RAID Action MPI_RAID_ACTION_DISABLE_VOLUME.
+ * 01-15-08 01.05.05 Added define for MPI_RAID_ACTION_SET_VOLUME_NAME.
* --------------------------------------------------------------------------
mpi_tool.h
@@ -694,6 +724,10 @@ mpi_sas.h
* reply.
* 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO
* Unit Control request.
+ * 01-15-08 01.05.05 Added support for MPI_SAS_OP_SET_IOC_PARAMETER,
+ * including adding IOCParameter and IOCParameter value
+ * fields to SAS IO Unit Control Request.
+ * Added MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC define.
* --------------------------------------------------------------------------
mpi_type.h
@@ -709,20 +743,20 @@ mpi_type.h
mpi_history.txt Parts list history
-Filename 01.05.15 01.05.15
----------- -------- --------
-mpi.h 01.05.12 01.05.13
-mpi_ioc.h 01.05.13 01.05.14
-mpi_cnfg.h 01.05.14 01.05.15
-mpi_init.h 01.05.09 01.05.09
-mpi_targ.h 01.05.06 01.05.06
-mpi_fc.h 01.05.01 01.05.01
-mpi_lan.h 01.05.01 01.05.01
-mpi_raid.h 01.05.03 01.05.03
-mpi_tool.h 01.05.03 01.05.03
-mpi_inb.h 01.05.01 01.05.01
-mpi_sas.h 01.05.04 01.05.04
-mpi_type.h 01.05.02 01.05.02
+Filename 01.05.19 01.05.18 01.05.17 01.05.16 01.05.15
+---------- -------- -------- -------- -------- --------
+mpi.h 01.05.16 01.05.15 01.05.14 01.05.13 01.05.12
+mpi_ioc.h 01.05.16 01.05.15 01.05.15 01.05.14 01.05.13
+mpi_cnfg.h 01.05.18 01.05.17 01.05.16 01.05.15 01.05.14
+mpi_init.h 01.05.09 01.05.09 01.05.09 01.05.09 01.05.09
+mpi_targ.h 01.05.06 01.05.06 01.05.06 01.05.06 01.05.06
+mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
+mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
+mpi_raid.h 01.05.05 01.05.05 01.05.04 01.05.03 01.05.03
+mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03
+mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
+mpi_sas.h 01.05.05 01.05.05 01.05.04 01.05.04 01.05.04
+mpi_type.h 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02
Filename 01.05.14 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09
---------- -------- -------- -------- -------- -------- --------
diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h
index a9e3693601a7..4295d062caa7 100644
--- a/drivers/message/fusion/lsi/mpi_init.h
+++ b/drivers/message/fusion/lsi/mpi_init.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2007 LSI Corporation.
+ * Copyright (c) 2000-2008 LSI Corporation.
*
*
* Name: mpi_init.h
diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h
index 5cbb6bd048e1..8faa4fab7b89 100644
--- a/drivers/message/fusion/lsi/mpi_ioc.h
+++ b/drivers/message/fusion/lsi/mpi_ioc.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2007 LSI Corporation.
+ * Copyright (c) 2000-2008 LSI Corporation.
*
*
* Name: mpi_ioc.h
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: August 11, 2000
*
- * mpi_ioc.h Version: 01.05.14
+ * mpi_ioc.h Version: 01.05.16
*
* Version History
* ---------------
@@ -113,6 +113,16 @@
* added _MULTI_PORT_DOMAIN.
* 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request.
* Added Common Boot Block type to FWUpload Request.
+ * 08-07-07 01.05.15 Added MPI_EVENT_SAS_INIT_RC_REMOVED define.
+ * Added MPI_EVENT_IR2_RC_DUAL_PORT_ADDED and
+ * MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED for IR2 event data.
+ * Added SASAddress field to SAS Initiator Device Table
+ * Overflow event data structure.
+ * 03-28-08 01.05.16 Added two new ReasonCode values to SAS Device Status
+ * Change Event data to indicate completion of internally
+ * generated task management.
+ * Added MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE define.
+ * Added MPI_EVENT_SAS_INIT_RC_INACCESSIBLE define.
* --------------------------------------------------------------------------
*/
@@ -612,6 +622,8 @@ typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
#define MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B)
#define MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C)
#define MPI_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D)
+#define MPI_EVENT_SAS_DEV_STAT_RC_CMPL_INTERNAL_DEV_RESET (0x0E)
+#define MPI_EVENT_SAS_DEV_STAT_RC_CMPL_TASK_ABORT_INTERNAL (0x0F)
/* SCSI Event data for Queue Full event */
@@ -708,6 +720,8 @@ typedef struct _MPI_EVENT_DATA_IR2
#define MPI_EVENT_IR2_RC_PD_REMOVED (0x05)
#define MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED (0x06)
#define MPI_EVENT_IR2_RC_REBUILD_MEDIUM_ERROR (0x07)
+#define MPI_EVENT_IR2_RC_DUAL_PORT_ADDED (0x08)
+#define MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED (0x09)
/* defines for logical disk states */
#define MPI_LD_STATE_OPTIMAL (0x00)
@@ -867,6 +881,7 @@ typedef struct _EVENT_DATA_DISCOVERY_ERROR
#define MPI_EVENT_DSCVRY_ERR_DS_UNSUPPORTED_DEVICE (0x00000800)
#define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000)
#define MPI_EVENT_DSCVRY_ERR_DS_MULTI_PORT_DOMAIN (0x00002000)
+#define MPI_EVENT_DSCVRY_ERR_DS_SATA_INIT_FAILURE (0x00004000)
/* SAS SMP Error Event data */
@@ -902,6 +917,8 @@ typedef struct _EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE
/* defines for the ReasonCode field of the SAS Initiator Device Status Change event */
#define MPI_EVENT_SAS_INIT_RC_ADDED (0x01)
+#define MPI_EVENT_SAS_INIT_RC_REMOVED (0x02)
+#define MPI_EVENT_SAS_INIT_RC_INACCESSIBLE (0x03)
/* SAS Initiator Device Table Overflow Event data */
@@ -910,6 +927,7 @@ typedef struct _EVENT_DATA_SAS_INIT_TABLE_OVERFLOW
U8 MaxInit; /* 00h */
U8 CurrentInit; /* 01h */
U16 Reserved1; /* 02h */
+ U64 SASAddress; /* 04h */
} EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
MPI_POINTER PTR_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
MpiEventDataSasInitTableOverflow_t,
diff --git a/drivers/message/fusion/lsi/mpi_lan.h b/drivers/message/fusion/lsi/mpi_lan.h
index 03253b53b785..f41fcb69b359 100644
--- a/drivers/message/fusion/lsi/mpi_lan.h
+++ b/drivers/message/fusion/lsi/mpi_lan.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 LSI Corporation.
+ * Copyright (c) 2000-2008 LSI Corporation.
*
*
* Name: mpi_lan.h
diff --git a/drivers/message/fusion/lsi/mpi_log_fc.h b/drivers/message/fusion/lsi/mpi_log_fc.h
index e4dafcefeecd..face6e7acc72 100644
--- a/drivers/message/fusion/lsi/mpi_log_fc.h
+++ b/drivers/message/fusion/lsi/mpi_log_fc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2001 LSI Corporation. All rights reserved.
+ * Copyright (c) 2000-2008 LSI Corporation. All rights reserved.
*
* NAME: fc_log.h
* SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips
diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h
index af9da03e95e5..691620dbedd2 100644
--- a/drivers/message/fusion/lsi/mpi_log_sas.h
+++ b/drivers/message/fusion/lsi/mpi_log_sas.h
@@ -1,6 +1,6 @@
/***************************************************************************
* *
- * Copyright 2003 LSI Corporation. All rights reserved. *
+ * Copyright (c) 2000-2008 LSI Corporation. All rights reserved. *
* *
* Description *
* ------------ *
@@ -73,6 +73,8 @@
#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO (0x00070004)
#define IOP_LOGINFO_CODE_TARGET_MODE_ABORT_EXACT_IO_REQ (0x00070005)
+#define IOP_LOGINFO_CODE_LOG_TIMESTAMP_EVENT (0x00080000)
+
/****************************************************************************/
/* PL LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = PL */
/****************************************************************************/
@@ -92,7 +94,7 @@
#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_OPEN_TIMEOUT_EXP (0x0000000C)
#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_UNUSED_0D (0x0000000D)
#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_DVTBLE_ACCSS_FAIL (0x0000000E)
-#define PL_LOGINFO_SUB CODE_OPEN_FAIL_BAD_DEST (0x00000011)
+#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_BAD_DEST (0x00000011)
#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RATE_NOT_SUPP (0x00000012)
#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_PROT_NOT_SUPP (0x00000013)
#define PL_LOGINFO_SUB_CODE_OPEN_FAIL_RESERVED_ABANDON0 (0x00000014)
@@ -159,10 +161,11 @@
#define PL_LOGINFO_SUB_CODE_INVALID_SGL (0x00000200)
#define PL_LOGINFO_SUB_CODE_WRONG_REL_OFF_OR_FRAME_LENGTH (0x00000300)
-#define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR (0x00000400) /* Bits 0-3 encode Transport Status Register (offset 0x08) */
- /* Bit 0 is Status Bit 0: FrameXferErr */
- /* Bit 1 & 2 are Status Bits 16 and 17: FrameXmitErrStatus */
- /* Bit 3 is Status Bit 18 WriteDataLengthGTDataLengthErr */
+#define PL_LOGINFO_SUB_CODE_FRAME_XFER_ERROR (0x00000400)
+/* Bits 0-3 encode Transport Status Register (offset 0x08) */
+/* Bit 0 is Status Bit 0: FrameXferErr */
+/* Bit 1 & 2 are Status Bits 16 and 17: FrameXmitErrStatus */
+/* Bit 3 is Status Bit 18 WriteDataLenghtGTDataLengthErr */
#define PL_LOGINFO_SUB_CODE_TX_FM_CONNECTED_LOW (0x00000500)
#define PL_LOGINFO_SUB_CODE_SATA_NON_NCQ_RW_ERR_BIT_SET (0x00000600)
@@ -177,6 +180,11 @@
#define PL_LOGINFO_SUB_CODE_DISCOVERY_REMOTE_SEP_RESET (0x00000E01)
#define PL_LOGINFO_SUB_CODE_SECOND_OPEN (0x00000F00)
#define PL_LOGINFO_SUB_CODE_DSCVRY_SATA_INIT_TIMEOUT (0x00001000)
+#define PL_LOGINFO_SUB_CODE_BREAK_ON_SATA_CONNECTION (0x00002000)
+/* not currently used in mainline */
+#define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK (0x00003000)
+#define PL_LOGINFO_SUB_CODE_BREAK_ON_STUCK_LINK_AIP (0x00004000)
+#define PL_LOGINFO_SUB_CODE_BREAK_ON_INCOMPLETE_BREAK_RCVD (0x00005000)
#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE (0x00200000) /* Can't get SMP Frame */
#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR (0x00200010) /* Error occured on SMP Read */
@@ -243,6 +251,8 @@
#define IR_LOGINFO_VOLUME_ACTIVATE_VOLUME_FAILED (0x00010014)
/* Activation failed trying to import the volume */
#define IR_LOGINFO_VOLUME_ACTIVATING_IMPORT_VOLUME_FAILED (0x00010015)
+/* Activation failed trying to import the volume */
+#define IR_LOGINFO_VOLUME_ACTIVATING_TOO_MANY_PHYS_DISKS (0x00010016)
/* Phys Disk failed, too many phys disks */
#define IR_LOGINFO_PHYSDISK_CREATE_TOO_MANY_DISKS (0x00010020)
@@ -285,6 +295,21 @@
/* Compatibility Error : IME size limited to < 2TB */
#define IR_LOGINFO_COMPAT_ERROR_IME_VOL_NOT_CURRENTLY_SUPPORTED (0x0001003D)
+/* Device Firmware Update: DFU can only be started once */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_DFU_IN_PROGRESS (0x00010050)
+/* Device Firmware Update: Volume must be Optimal/Active/non-Quiesced */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_DEVICE_IN_INVALID_STATE (0x00010051)
+/* Device Firmware Update: DFU Timeout cannot be zero */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_INVALID_TIMEOUT (0x00010052)
+/* Device Firmware Update: CREATE TIMER FAILED */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_NO_TIMERS (0x00010053)
+/* Device Firmware Update: Failed to read SAS_IO_UNIT_PG_1 */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_READING_CFG_PAGE (0x00010054)
+/* Device Firmware Update: Invalid SAS_IO_UNIT_PG_1 value(s) */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_PORT_IO_TIMEOUTS_REQUIRED (0x00010055)
+/* Device Firmware Update: Unable to allocate memory for page */
+#define IR_LOGINFO_DEV_FW_UPDATE_ERR_ALLOC_CFG_PAGE (0x00010056)
+
/****************************************************************************/
/* Defines for convenience */
diff --git a/drivers/message/fusion/lsi/mpi_raid.h b/drivers/message/fusion/lsi/mpi_raid.h
index 2856108421d7..add60cc85be1 100644
--- a/drivers/message/fusion/lsi/mpi_raid.h
+++ b/drivers/message/fusion/lsi/mpi_raid.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2001-2007 LSI Corporation.
+ * Copyright (c) 2001-2008 LSI Corporation.
*
*
* Name: mpi_raid.h
* Title: MPI RAID message and structures
* Creation Date: February 27, 2001
*
- * mpi_raid.h Version: 01.05.03
+ * mpi_raid.h Version: 01.05.05
*
* Version History
* ---------------
@@ -34,6 +34,9 @@
* _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE.
* 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and
* associated defines.
+ * 08-07-07 01.05.04 Added Disable Full Rebuild bit to the ActionDataWord
+ * for the RAID Action MPI_RAID_ACTION_DISABLE_VOLUME.
+ * 01-15-08 01.05.05 Added define for MPI_RAID_ACTION_SET_VOLUME_NAME.
* --------------------------------------------------------------------------
*/
@@ -93,6 +96,7 @@ typedef struct _MSG_RAID_ACTION
#define MPI_RAID_ACTION_SET_RESYNC_RATE (0x13)
#define MPI_RAID_ACTION_SET_DATA_SCRUB_RATE (0x14)
#define MPI_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15)
+#define MPI_RAID_ACTION_SET_VOLUME_NAME (0x16)
/* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */
#define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC (0x00000001)
@@ -105,6 +109,9 @@ typedef struct _MSG_RAID_ACTION
#define MPI_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000)
#define MPI_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000002)
+/* ActionDataWord defines for use with MPI_RAID_ACTION_DISABLE_VOLUME action */
+#define MPI_RAID_ACTION_ADATA_DISABLE_FULL_REBUILD (0x00000001)
+
/* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */
#define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL (0x00000001)
diff --git a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h
index 33fca83cefc2..ab410036bbfc 100644
--- a/drivers/message/fusion/lsi/mpi_sas.h
+++ b/drivers/message/fusion/lsi/mpi_sas.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2004-2006 LSI Corporation.
+ * Copyright (c) 2004-2008 LSI Corporation.
*
*
* Name: mpi_sas.h
* Title: MPI Serial Attached SCSI structures and definitions
* Creation Date: August 19, 2004
*
- * mpi_sas.h Version: 01.05.04
+ * mpi_sas.h Version: 01.05.05
*
* Version History
* ---------------
@@ -23,6 +23,10 @@
* reply.
* 10-11-06 01.05.04 Fixed the name of a define for Operation field of SAS IO
* Unit Control request.
+ * 01-15-08 01.05.05 Added support for MPI_SAS_OP_SET_IOC_PARAMETER,
+ * including adding IOCParameter and IOCParameter value
+ * fields to SAS IO Unit Control Request.
+ * Added MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC define.
* --------------------------------------------------------------------------
*/
@@ -60,6 +64,8 @@
* Values for the SAS DeviceInfo field used in SAS Device Status Change Event
* data and SAS IO Unit Configuration pages.
*/
+#define MPI_SAS_DEVICE_INFO_PRODUCT_SPECIFIC (0xF0000000)
+
#define MPI_SAS_DEVICE_INFO_SEP (0x00004000)
#define MPI_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000)
#define MPI_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000)
@@ -216,7 +222,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST
U8 ChainOffset; /* 02h */
U8 Function; /* 03h */
U16 DevHandle; /* 04h */
- U8 Reserved3; /* 06h */
+ U8 IOCParameter; /* 06h */
U8 MsgFlags; /* 07h */
U32 MsgContext; /* 08h */
U8 TargetID; /* 0Ch */
@@ -225,7 +231,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST
U8 PrimFlags; /* 0Fh */
U32 Primitive; /* 10h */
U64 SASAddress; /* 14h */
- U32 Reserved4; /* 1Ch */
+ U32 IOCParameterValue; /* 1Ch */
} MSG_SAS_IOUNIT_CONTROL_REQUEST, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REQUEST,
SasIoUnitControlRequest_t, MPI_POINTER pSasIoUnitControlRequest_t;
@@ -241,6 +247,8 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST
#define MPI_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C)
#define MPI_SAS_OP_TRANSMIT_REMOVE_DEVICE (0x0D) /* obsolete name */
#define MPI_SAS_OP_REMOVE_DEVICE (0x0D)
+#define MPI_SAS_OP_SET_IOC_PARAMETER (0x0E)
+#define MPI_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80)
/* values for the PrimFlags field */
#define MPI_SAS_PRIMFLAGS_SINGLE (0x08)
@@ -256,7 +264,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REPLY
U8 MsgLength; /* 02h */
U8 Function; /* 03h */
U16 DevHandle; /* 04h */
- U8 Reserved3; /* 06h */
+ U8 IOCParameter; /* 06h */
U8 MsgFlags; /* 07h */
U32 MsgContext; /* 08h */
U16 Reserved4; /* 0Ch */
diff --git a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h
index ff8c37d3fdcb..c3dea7f6909d 100644
--- a/drivers/message/fusion/lsi/mpi_targ.h
+++ b/drivers/message/fusion/lsi/mpi_targ.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2004 LSI Corporation.
+ * Copyright (c) 2000-2008 LSI Corporation.
*
*
* Name: mpi_targ.h
diff --git a/drivers/message/fusion/lsi/mpi_tool.h b/drivers/message/fusion/lsi/mpi_tool.h
index 8834ae6ce0f2..53cd715aa7e4 100644
--- a/drivers/message/fusion/lsi/mpi_tool.h
+++ b/drivers/message/fusion/lsi/mpi_tool.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2005 LSI Corporation.
+ * Copyright (c) 2001-2008 LSI Corporation.
*
*
* Name: mpi_tool.h
diff --git a/drivers/message/fusion/lsi/mpi_type.h b/drivers/message/fusion/lsi/mpi_type.h
index 08dad9c1e446..888b26dbc413 100644
--- a/drivers/message/fusion/lsi/mpi_type.h
+++ b/drivers/message/fusion/lsi/mpi_type.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2004 LSI Corporation.
+ * Copyright (c) 2000-2008 LSI Corporation.
*
*
* Name: mpi_type.h
* Title: MPI Basic type definitions
* Creation Date: June 6, 2000
*
- * mpi_type.h Version: 01.05.01
+ * mpi_type.h Version: 01.05.02
*
* Version History
* ---------------
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index c4e8b9aa3827..96ac88317b8e 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -79,9 +79,22 @@ MODULE_VERSION(my_VERSION);
/*
* cmd line parameters
*/
-static int mpt_msi_enable = -1;
-module_param(mpt_msi_enable, int, 0);
-MODULE_PARM_DESC(mpt_msi_enable, " MSI Support Enable (default=0)");
+
+static int mpt_msi_enable_spi;
+module_param(mpt_msi_enable_spi, int, 0);
+MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI \
+ controllers (default=0)");
+
+static int mpt_msi_enable_fc;
+module_param(mpt_msi_enable_fc, int, 0);
+MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \
+ controllers (default=0)");
+
+static int mpt_msi_enable_sas;
+module_param(mpt_msi_enable_sas, int, 1);
+MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
+ controllers (default=1)");
+
static int mpt_channel_mapping;
module_param(mpt_channel_mapping, int, 0);
@@ -91,7 +104,17 @@ static int mpt_debug_level;
static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
&mpt_debug_level, 0600);
-MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)");
+MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \
+ - (default=0)");
+
+int mpt_fwfault_debug;
+EXPORT_SYMBOL(mpt_fwfault_debug);
+module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
+ &mpt_fwfault_debug, 0600);
+MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
+ " and halt Firmware on fault - (default=0)");
+
+
#ifdef MFCNT
static int mfcounter = 0;
@@ -1751,16 +1774,25 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->bus_type = SAS;
}
- if (mpt_msi_enable == -1) {
- /* Enable on SAS, disable on FC and SPI */
- if (ioc->bus_type == SAS)
- ioc->msi_enable = 1;
- else
- ioc->msi_enable = 0;
- } else
- /* follow flag: 0 - disable; 1 - enable */
- ioc->msi_enable = mpt_msi_enable;
+ switch (ioc->bus_type) {
+
+ case SAS:
+ ioc->msi_enable = mpt_msi_enable_sas;
+ break;
+
+ case SPI:
+ ioc->msi_enable = mpt_msi_enable_spi;
+ break;
+
+ case FC:
+ ioc->msi_enable = mpt_msi_enable_fc;
+ break;
+
+ default:
+ ioc->msi_enable = 0;
+ break;
+ }
if (ioc->errata_flag_1064)
pci_disable_io_access(pdev);
@@ -6313,6 +6345,33 @@ mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buffer, int *size, int len, int sh
*size = y;
}
+
+/**
+ * mpt_halt_firmware - Halts the firmware if it is operational and panic
+ * the kernel
+ * @ioc: Pointer to MPT_ADAPTER structure
+ *
+ **/
+void
+mpt_halt_firmware(MPT_ADAPTER *ioc)
+{
+ u32 ioc_raw_state;
+
+ ioc_raw_state = mpt_GetIocState(ioc, 0);
+
+ if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) {
+ printk(MYIOC_s_ERR_FMT "IOC is in FAULT state (%04xh)!!!\n",
+ ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK);
+ panic("%s: IOC Fault (%04xh)!!!\n", ioc->name,
+ ioc_raw_state & MPI_DOORBELL_DATA_MASK);
+ } else {
+ CHIPREG_WRITE32(&ioc->chip->Doorbell, 0xC0FFEE00);
+ panic("%s: Firmware is halted due to command timeout\n",
+ ioc->name);
+ }
+}
+EXPORT_SYMBOL(mpt_halt_firmware);
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* Reset Handling
@@ -6345,6 +6404,8 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
printk("MF count 0x%x !\n", ioc->mfcnt);
#endif
+ if (mpt_fwfault_debug)
+ mpt_halt_firmware(ioc);
/* Reset the adapter. Prevent more than 1 call to
* mpt_do_ioc_recovery at any instant in time.
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index dff048cfa101..b3e981d2a506 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -922,11 +922,14 @@ 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);
extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk);
+extern void mpt_halt_firmware(MPT_ADAPTER *ioc);
+
/*
* Public data decl's...
*/
extern struct list_head ioc_list;
+extern int mpt_fwfault_debug;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#endif /* } __KERNEL__ */
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index b89f476cd0a9..c63817117c0a 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -308,10 +308,11 @@ static void mptctl_timeout_expired (MPT_IOCTL *ioctl)
{
int rc = 1;
- dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n",
- ioctl->ioc->name, ioctl->ioc->id));
if (ioctl == NULL)
return;
+ dctlprintk(ioctl->ioc,
+ printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n",
+ ioctl->ioc->name, ioctl->ioc->id));
ioctl->wait_done = 0;
if (ioctl->reset & MPTCTL_RESET_OK)
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index a13f6eecd25b..c2804f26cb44 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -106,7 +106,6 @@ struct mpt_lan_priv {
u32 total_posted;
u32 total_received;
- struct net_device_stats stats; /* Per device statistics */
struct delayed_work post_buckets_task;
struct net_device *dev;
@@ -548,15 +547,6 @@ mpt_lan_close(struct net_device *dev)
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-static struct net_device_stats *
-mpt_lan_get_stats(struct net_device *dev)
-{
- struct mpt_lan_priv *priv = netdev_priv(dev);
-
- return (struct net_device_stats *) &priv->stats;
-}
-
-/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static int
mpt_lan_change_mtu(struct net_device *dev, int new_mtu)
{
@@ -594,8 +584,8 @@ mpt_lan_send_turbo(struct net_device *dev, u32 tmsg)
ctx = GET_LAN_BUFFER_CONTEXT(tmsg);
sent = priv->SendCtl[ctx].skb;
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += sent->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += sent->len;
dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
IOC_AND_NETDEV_NAMES_s_s(dev),
@@ -636,7 +626,7 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep)
switch (le16_to_cpu(pSendRep->IOCStatus) & MPI_IOCSTATUS_MASK) {
case MPI_IOCSTATUS_SUCCESS:
- priv->stats.tx_packets += count;
+ dev->stats.tx_packets += count;
break;
case MPI_IOCSTATUS_LAN_CANCELED:
@@ -644,13 +634,13 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep)
break;
case MPI_IOCSTATUS_INVALID_SGL:
- priv->stats.tx_errors += count;
+ dev->stats.tx_errors += count;
printk (KERN_ERR MYNAM ": %s/%s: ERROR - Invalid SGL sent to IOC!\n",
IOC_AND_NETDEV_NAMES_s_s(dev));
goto out;
default:
- priv->stats.tx_errors += count;
+ dev->stats.tx_errors += count;
break;
}
@@ -661,7 +651,7 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep)
ctx = GET_LAN_BUFFER_CONTEXT(le32_to_cpu(*pContext));
sent = priv->SendCtl[ctx].skb;
- priv->stats.tx_bytes += sent->len;
+ dev->stats.tx_bytes += sent->len;
dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n",
IOC_AND_NETDEV_NAMES_s_s(dev),
@@ -842,8 +832,8 @@ mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb)
"delivered to upper level.\n",
IOC_AND_NETDEV_NAMES_s_s(dev), skb->len));
- priv->stats.rx_bytes += skb->len;
- priv->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
skb->dev = dev;
netif_rx(skb);
@@ -1308,6 +1298,14 @@ mpt_lan_post_receive_buckets_work(struct work_struct *work)
post_buckets_task.work));
}
+static const struct net_device_ops mpt_netdev_ops = {
+ .ndo_open = mpt_lan_open,
+ .ndo_stop = mpt_lan_close,
+ .ndo_start_xmit = mpt_lan_sdu_send,
+ .ndo_change_mtu = mpt_lan_change_mtu,
+ .ndo_tx_timeout = mpt_lan_tx_timeout,
+};
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
static struct net_device *
mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
@@ -1372,15 +1370,7 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum)
priv->tx_max_out = (tx_max_out_p <= MPT_TX_MAX_OUT_LIM) ?
tx_max_out_p : MPT_TX_MAX_OUT_LIM;
- dev->open = mpt_lan_open;
- dev->stop = mpt_lan_close;
- dev->get_stats = mpt_lan_get_stats;
- dev->set_multicast_list = NULL;
- dev->change_mtu = mpt_lan_change_mtu;
- dev->hard_start_xmit = mpt_lan_sdu_send;
-
-/* Not in 2.3.42. Need 2.3.45+ */
- dev->tx_timeout = mpt_lan_tx_timeout;
+ dev->netdev_ops = &mpt_netdev_ops;
dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT;
dlprintk((KERN_INFO MYNAM ": Finished registering dev "
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index ee090413e598..e62c6bc4ad33 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -1846,6 +1846,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
if (hd->timeouts < -1)
hd->timeouts++;
+ if (mpt_fwfault_debug)
+ mpt_halt_firmware(ioc);
+
/* Most important! Set TaskMsgContext to SCpnt's MsgContext!
* (the IO to be ABORT'd)
*
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
index 1bcdbbb9e7d3..3d45817e6dcd 100644
--- a/drivers/message/i2o/i2o_scsi.c
+++ b/drivers/message/i2o/i2o_scsi.c
@@ -390,7 +390,7 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
* @i2o_dev: the I2O device which was added
*
* If a I2O device is added we catch the notification, because I2O classes
- * other then SCSI peripheral will not be received through
+ * other than SCSI peripheral will not be received through
* i2o_scsi_probe().
*/
static void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev)
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 416f9e7286ba..06a2b0f7737c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -217,6 +217,29 @@ config MFD_WM8350_I2C
I2C as the control interface. Additional options must be
selected to enable support for the functionality of the chip.
+config MFD_PCF50633
+ tristate "Support for NXP PCF50633"
+ depends on I2C
+ help
+ Say yes here if you have NXP PCF50633 chip on your board.
+ This core driver provides register access and IRQ handling
+ facilities, and registers devices for the various functions
+ so that function-specific drivers can bind to them.
+
+config PCF50633_ADC
+ tristate "Support for NXP PCF50633 ADC"
+ depends on MFD_PCF50633
+ help
+ Say yes here if you want to include support for ADC in the
+ NXP PCF50633 chip.
+
+config PCF50633_GPIO
+ tristate "Support for NXP PCF50633 GPIO"
+ depends on MFD_PCF50633
+ help
+ Say yes here if you want to include support GPIO for pins on
+ the PCF50633 chip.
+
endmenu
menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 0c9418b36c26..3afb5192e4da 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -37,3 +37,7 @@ endif
obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o
obj-$(CONFIG_PMIC_DA903X) += da903x.o
+
+obj-$(CONFIG_MFD_PCF50633) += pcf50633-core.o
+obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
+obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o \ No newline at end of file
diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c
index 4214b3f72426..7ac12cb0be4a 100644
--- a/drivers/mfd/dm355evm_msp.c
+++ b/drivers/mfd/dm355evm_msp.c
@@ -107,6 +107,9 @@ static const u8 msp_gpios[] = {
MSP_GPIO(0, SWITCH1), MSP_GPIO(1, SWITCH1),
MSP_GPIO(2, SWITCH1), MSP_GPIO(3, SWITCH1),
MSP_GPIO(4, SWITCH1),
+ /* switches on MMC/SD sockets */
+ MSP_GPIO(1, SDMMC), MSP_GPIO(2, SDMMC), /* mmc0 WP, nCD */
+ MSP_GPIO(3, SDMMC), MSP_GPIO(4, SDMMC), /* mmc1 WP, nCD */
};
#define MSP_GPIO_REG(offset) (msp_gpios[(offset)] >> 3)
@@ -304,6 +307,13 @@ static int add_children(struct i2c_client *client)
gpio_export(gpio, false);
}
+ /* MMC/SD inputs -- right after the last config input */
+ if (client->dev.platform_data) {
+ void (*mmcsd_setup)(unsigned) = client->dev.platform_data;
+
+ mmcsd_setup(dm355evm_msp_gpio.base + 8 + 5);
+ }
+
/* RTC is a 32 bit counter, no alarm */
if (msp_has_rtc()) {
child = add_child(client, "rtc-dm355evm",
diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c
new file mode 100644
index 000000000000..c2d05becfa97
--- /dev/null
+++ b/drivers/mfd/pcf50633-adc.c
@@ -0,0 +1,277 @@
+/* NXP PCF50633 ADC Driver
+ *
+ * (C) 2006-2008 by Openmoko, Inc.
+ * Author: Balaji Rao <balajirrao@openmoko.org>
+ * All rights reserved.
+ *
+ * Broken down from monstrous PCF50633 driver mainly by
+ * Harald Welte, Andy Green and Werner Almesberger
+ *
+ * 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.
+ *
+ * NOTE: This driver does not yet support subtractive ADC mode, which means
+ * you can do only one measurement per read request.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+
+#include <linux/mfd/pcf50633/core.h>
+#include <linux/mfd/pcf50633/adc.h>
+
+struct pcf50633_adc_request {
+ int mux;
+ int avg;
+ int result;
+ void (*callback)(struct pcf50633 *, void *, int);
+ void *callback_param;
+
+ /* Used in case of sync requests */
+ struct completion completion;
+
+};
+
+#define PCF50633_MAX_ADC_FIFO_DEPTH 8
+
+struct pcf50633_adc {
+ struct pcf50633 *pcf;
+
+ /* Private stuff */
+ struct pcf50633_adc_request *queue[PCF50633_MAX_ADC_FIFO_DEPTH];
+ int queue_head;
+ int queue_tail;
+ struct mutex queue_mutex;
+};
+
+static inline struct pcf50633_adc *__to_adc(struct pcf50633 *pcf)
+{
+ return platform_get_drvdata(pcf->adc_pdev);
+}
+
+static void adc_setup(struct pcf50633 *pcf, int channel, int avg)
+{
+ channel &= PCF50633_ADCC1_ADCMUX_MASK;
+
+ /* kill ratiometric, but enable ACCSW biasing */
+ pcf50633_reg_write(pcf, PCF50633_REG_ADCC2, 0x00);
+ pcf50633_reg_write(pcf, PCF50633_REG_ADCC3, 0x01);
+
+ /* start ADC conversion on selected channel */
+ pcf50633_reg_write(pcf, PCF50633_REG_ADCC1, channel | avg |
+ PCF50633_ADCC1_ADCSTART | PCF50633_ADCC1_RES_10BIT);
+}
+
+static void trigger_next_adc_job_if_any(struct pcf50633 *pcf)
+{
+ struct pcf50633_adc *adc = __to_adc(pcf);
+ int head;
+
+ mutex_lock(&adc->queue_mutex);
+
+ head = adc->queue_head;
+
+ if (!adc->queue[head]) {
+ mutex_unlock(&adc->queue_mutex);
+ return;
+ }
+ mutex_unlock(&adc->queue_mutex);
+
+ adc_setup(pcf, adc->queue[head]->mux, adc->queue[head]->avg);
+}
+
+static int
+adc_enqueue_request(struct pcf50633 *pcf, struct pcf50633_adc_request *req)
+{
+ struct pcf50633_adc *adc = __to_adc(pcf);
+ int head, tail;
+
+ mutex_lock(&adc->queue_mutex);
+
+ head = adc->queue_head;
+ tail = adc->queue_tail;
+
+ if (adc->queue[tail]) {
+ mutex_unlock(&adc->queue_mutex);
+ return -EBUSY;
+ }
+
+ adc->queue[tail] = req;
+ adc->queue_tail = (tail + 1) & (PCF50633_MAX_ADC_FIFO_DEPTH - 1);
+
+ mutex_unlock(&adc->queue_mutex);
+
+ trigger_next_adc_job_if_any(pcf);
+
+ return 0;
+}
+
+static void
+pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, int result)
+{
+ struct pcf50633_adc_request *req = param;
+
+ req->result = result;
+ complete(&req->completion);
+}
+
+int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg)
+{
+ struct pcf50633_adc_request *req;
+
+ /* req is freed when the result is ready, in interrupt handler */
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ req->mux = mux;
+ req->avg = avg;
+ req->callback = pcf50633_adc_sync_read_callback;
+ req->callback_param = req;
+
+ init_completion(&req->completion);
+ adc_enqueue_request(pcf, req);
+ wait_for_completion(&req->completion);
+
+ return req->result;
+}
+EXPORT_SYMBOL_GPL(pcf50633_adc_sync_read);
+
+int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg,
+ void (*callback)(struct pcf50633 *, void *, int),
+ void *callback_param)
+{
+ struct pcf50633_adc_request *req;
+
+ /* req is freed when the result is ready, in interrupt handler */
+ req = kmalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ req->mux = mux;
+ req->avg = avg;
+ req->callback = callback;
+ req->callback_param = callback_param;
+
+ adc_enqueue_request(pcf, req);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pcf50633_adc_async_read);
+
+static int adc_result(struct pcf50633 *pcf)
+{
+ u8 adcs1, adcs3;
+ u16 result;
+
+ adcs1 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS1);
+ adcs3 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS3);
+ result = (adcs1 << 2) | (adcs3 & PCF50633_ADCS3_ADCDAT1L_MASK);
+
+ dev_dbg(pcf->dev, "adc result = %d\n", result);
+
+ return result;
+}
+
+static void pcf50633_adc_irq(int irq, void *data)
+{
+ struct pcf50633_adc *adc = data;
+ struct pcf50633 *pcf = adc->pcf;
+ struct pcf50633_adc_request *req;
+ int head;
+
+ mutex_lock(&adc->queue_mutex);
+ head = adc->queue_head;
+
+ req = adc->queue[head];
+ if (WARN_ON(!req)) {
+ dev_err(pcf->dev, "pcf50633-adc irq: ADC queue empty!\n");
+ mutex_unlock(&adc->queue_mutex);
+ return;
+ }
+ adc->queue[head] = NULL;
+ adc->queue_head = (head + 1) &
+ (PCF50633_MAX_ADC_FIFO_DEPTH - 1);
+
+ mutex_unlock(&adc->queue_mutex);
+
+ req->callback(pcf, req->callback_param, adc_result(pcf));
+ kfree(req);
+
+ trigger_next_adc_job_if_any(pcf);
+}
+
+static int __devinit pcf50633_adc_probe(struct platform_device *pdev)
+{
+ struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
+ struct pcf50633_adc *adc;
+
+ adc = kzalloc(sizeof(*adc), GFP_KERNEL);
+ if (!adc)
+ return -ENOMEM;
+
+ adc->pcf = pdata->pcf;
+ platform_set_drvdata(pdev, adc);
+
+ pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ADCRDY,
+ pcf50633_adc_irq, adc);
+
+ mutex_init(&adc->queue_mutex);
+
+ return 0;
+}
+
+static int __devexit pcf50633_adc_remove(struct platform_device *pdev)
+{
+ struct pcf50633_adc *adc = platform_get_drvdata(pdev);
+ int i, head;
+
+ pcf50633_free_irq(adc->pcf, PCF50633_IRQ_ADCRDY);
+
+ mutex_lock(&adc->queue_mutex);
+ head = adc->queue_head;
+
+ if (WARN_ON(adc->queue[head]))
+ dev_err(adc->pcf->dev,
+ "adc driver removed with request pending\n");
+
+ for (i = 0; i < PCF50633_MAX_ADC_FIFO_DEPTH; i++)
+ kfree(adc->queue[i]);
+
+ mutex_unlock(&adc->queue_mutex);
+ kfree(adc);
+
+ return 0;
+}
+
+static struct platform_driver pcf50633_adc_driver = {
+ .driver = {
+ .name = "pcf50633-adc",
+ },
+ .probe = pcf50633_adc_probe,
+ .remove = __devexit_p(pcf50633_adc_remove),
+};
+
+static int __init pcf50633_adc_init(void)
+{
+ return platform_driver_register(&pcf50633_adc_driver);
+}
+module_init(pcf50633_adc_init);
+
+static void __exit pcf50633_adc_exit(void)
+{
+ platform_driver_unregister(&pcf50633_adc_driver);
+}
+module_exit(pcf50633_adc_exit);
+
+MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
+MODULE_DESCRIPTION("PCF50633 adc driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcf50633-adc");
+
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c
new file mode 100644
index 000000000000..24508e28e3fb
--- /dev/null
+++ b/drivers/mfd/pcf50633-core.c
@@ -0,0 +1,710 @@
+/* NXP PCF50633 Power Management Unit (PMU) driver
+ *
+ * (C) 2006-2008 by Openmoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ * Balaji Rao <balajirrao@openmoko.org>
+ * 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/kernel.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+
+#include <linux/mfd/pcf50633/core.h>
+
+/* Two MBCS registers used during cold start */
+#define PCF50633_REG_MBCS1 0x4b
+#define PCF50633_REG_MBCS2 0x4c
+#define PCF50633_MBCS1_USBPRES 0x01
+#define PCF50633_MBCS1_ADAPTPRES 0x01
+
+static int __pcf50633_read(struct pcf50633 *pcf, u8 reg, int num, u8 *data)
+{
+ int ret;
+
+ ret = i2c_smbus_read_i2c_block_data(pcf->i2c_client, reg,
+ num, data);
+ if (ret < 0)
+ dev_err(pcf->dev, "Error reading %d regs at %d\n", num, reg);
+
+ return ret;
+}
+
+static int __pcf50633_write(struct pcf50633 *pcf, u8 reg, int num, u8 *data)
+{
+ int ret;
+
+ ret = i2c_smbus_write_i2c_block_data(pcf->i2c_client, reg,
+ num, data);
+ if (ret < 0)
+ dev_err(pcf->dev, "Error writing %d regs at %d\n", num, reg);
+
+ return ret;
+
+}
+
+/* Read a block of upto 32 regs */
+int pcf50633_read_block(struct pcf50633 *pcf, u8 reg,
+ int nr_regs, u8 *data)
+{
+ int ret;
+
+ mutex_lock(&pcf->lock);
+ ret = __pcf50633_read(pcf, reg, nr_regs, data);
+ mutex_unlock(&pcf->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pcf50633_read_block);
+
+/* Write a block of upto 32 regs */
+int pcf50633_write_block(struct pcf50633 *pcf , u8 reg,
+ int nr_regs, u8 *data)
+{
+ int ret;
+
+ mutex_lock(&pcf->lock);
+ ret = __pcf50633_write(pcf, reg, nr_regs, data);
+ mutex_unlock(&pcf->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pcf50633_write_block);
+
+u8 pcf50633_reg_read(struct pcf50633 *pcf, u8 reg)
+{
+ u8 val;
+
+ mutex_lock(&pcf->lock);
+ __pcf50633_read(pcf, reg, 1, &val);
+ mutex_unlock(&pcf->lock);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(pcf50633_reg_read);
+
+int pcf50633_reg_write(struct pcf50633 *pcf, u8 reg, u8 val)
+{
+ int ret;
+
+ mutex_lock(&pcf->lock);
+ ret = __pcf50633_write(pcf, reg, 1, &val);
+ mutex_unlock(&pcf->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pcf50633_reg_write);
+
+int pcf50633_reg_set_bit_mask(struct pcf50633 *pcf, u8 reg, u8 mask, u8 val)
+{
+ int ret;
+ u8 tmp;
+
+ val &= mask;
+
+ mutex_lock(&pcf->lock);
+ ret = __pcf50633_read(pcf, reg, 1, &tmp);
+ if (ret < 0)
+ goto out;
+
+ tmp &= ~mask;
+ tmp |= val;
+ ret = __pcf50633_write(pcf, reg, 1, &tmp);
+
+out:
+ mutex_unlock(&pcf->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pcf50633_reg_set_bit_mask);
+
+int pcf50633_reg_clear_bits(struct pcf50633 *pcf, u8 reg, u8 val)
+{
+ int ret;
+ u8 tmp;
+
+ mutex_lock(&pcf->lock);
+ ret = __pcf50633_read(pcf, reg, 1, &tmp);
+ if (ret < 0)
+ goto out;
+
+ tmp &= ~val;
+ ret = __pcf50633_write(pcf, reg, 1, &tmp);
+
+out:
+ mutex_unlock(&pcf->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pcf50633_reg_clear_bits);
+
+/* sysfs attributes */
+static ssize_t show_dump_regs(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct pcf50633 *pcf = dev_get_drvdata(dev);
+ u8 dump[16];
+ int n, n1, idx = 0;
+ char *buf1 = buf;
+ static u8 address_no_read[] = { /* must be ascending */
+ PCF50633_REG_INT1,
+ PCF50633_REG_INT2,
+ PCF50633_REG_INT3,
+ PCF50633_REG_INT4,
+ PCF50633_REG_INT5,
+ 0 /* terminator */
+ };
+
+ for (n = 0; n < 256; n += sizeof(dump)) {
+ for (n1 = 0; n1 < sizeof(dump); n1++)
+ if (n == address_no_read[idx]) {
+ idx++;
+ dump[n1] = 0x00;
+ } else
+ dump[n1] = pcf50633_reg_read(pcf, n + n1);
+
+ hex_dump_to_buffer(dump, sizeof(dump), 16, 1, buf1, 128, 0);
+ buf1 += strlen(buf1);
+ *buf1++ = '\n';
+ *buf1 = '\0';
+ }
+
+ return buf1 - buf;
+}
+static DEVICE_ATTR(dump_regs, 0400, show_dump_regs, NULL);
+
+static ssize_t show_resume_reason(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pcf50633 *pcf = dev_get_drvdata(dev);
+ int n;
+
+ n = sprintf(buf, "%02x%02x%02x%02x%02x\n",
+ pcf->resume_reason[0],
+ pcf->resume_reason[1],
+ pcf->resume_reason[2],
+ pcf->resume_reason[3],
+ pcf->resume_reason[4]);
+
+ return n;
+}
+static DEVICE_ATTR(resume_reason, 0400, show_resume_reason, NULL);
+
+static struct attribute *pcf_sysfs_entries[] = {
+ &dev_attr_dump_regs.attr,
+ &dev_attr_resume_reason.attr,
+ NULL,
+};
+
+static struct attribute_group pcf_attr_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = pcf_sysfs_entries,
+};
+
+int pcf50633_register_irq(struct pcf50633 *pcf, int irq,
+ void (*handler) (int, void *), void *data)
+{
+ if (irq < 0 || irq > PCF50633_NUM_IRQ || !handler)
+ return -EINVAL;
+
+ if (WARN_ON(pcf->irq_handler[irq].handler))
+ return -EBUSY;
+
+ mutex_lock(&pcf->lock);
+ pcf->irq_handler[irq].handler = handler;
+ pcf->irq_handler[irq].data = data;
+ mutex_unlock(&pcf->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pcf50633_register_irq);
+
+int pcf50633_free_irq(struct pcf50633 *pcf, int irq)
+{
+ if (irq < 0 || irq > PCF50633_NUM_IRQ)
+ return -EINVAL;
+
+ mutex_lock(&pcf->lock);
+ pcf->irq_handler[irq].handler = NULL;
+ mutex_unlock(&pcf->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pcf50633_free_irq);
+
+static int __pcf50633_irq_mask_set(struct pcf50633 *pcf, int irq, u8 mask)
+{
+ u8 reg, bits, tmp;
+ int ret = 0, idx;
+
+ idx = irq >> 3;
+ reg = PCF50633_REG_INT1M + idx;
+ bits = 1 << (irq & 0x07);
+
+ mutex_lock(&pcf->lock);
+
+ if (mask) {
+ ret = __pcf50633_read(pcf, reg, 1, &tmp);
+ if (ret < 0)
+ goto out;
+
+ tmp |= bits;
+
+ ret = __pcf50633_write(pcf, reg, 1, &tmp);
+ if (ret < 0)
+ goto out;
+
+ pcf->mask_regs[idx] &= ~bits;
+ pcf->mask_regs[idx] |= bits;
+ } else {
+ ret = __pcf50633_read(pcf, reg, 1, &tmp);
+ if (ret < 0)
+ goto out;
+
+ tmp &= ~bits;
+
+ ret = __pcf50633_write(pcf, reg, 1, &tmp);
+ if (ret < 0)
+ goto out;
+
+ pcf->mask_regs[idx] &= ~bits;
+ }
+out:
+ mutex_unlock(&pcf->lock);
+
+ return ret;
+}
+
+int pcf50633_irq_mask(struct pcf50633 *pcf, int irq)
+{
+ dev_info(pcf->dev, "Masking IRQ %d\n", irq);
+
+ return __pcf50633_irq_mask_set(pcf, irq, 1);
+}
+EXPORT_SYMBOL_GPL(pcf50633_irq_mask);
+
+int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq)
+{
+ dev_info(pcf->dev, "Unmasking IRQ %d\n", irq);
+
+ return __pcf50633_irq_mask_set(pcf, irq, 0);
+}
+EXPORT_SYMBOL_GPL(pcf50633_irq_unmask);
+
+int pcf50633_irq_mask_get(struct pcf50633 *pcf, int irq)
+{
+ u8 reg, bits;
+
+ reg = irq >> 3;
+ bits = 1 << (irq & 0x07);
+
+ return pcf->mask_regs[reg] & bits;
+}
+EXPORT_SYMBOL_GPL(pcf50633_irq_mask_get);
+
+static void pcf50633_irq_call_handler(struct pcf50633 *pcf, int irq)
+{
+ if (pcf->irq_handler[irq].handler)
+ pcf->irq_handler[irq].handler(irq, pcf->irq_handler[irq].data);
+}
+
+/* Maximum amount of time ONKEY is held before emergency action is taken */
+#define PCF50633_ONKEY1S_TIMEOUT 8
+
+static void pcf50633_irq_worker(struct work_struct *work)
+{
+ struct pcf50633 *pcf;
+ int ret, i, j;
+ u8 pcf_int[5], chgstat;
+
+ pcf = container_of(work, struct pcf50633, irq_work);
+
+ /* Read the 5 INT regs in one transaction */
+ ret = pcf50633_read_block(pcf, PCF50633_REG_INT1,
+ ARRAY_SIZE(pcf_int), pcf_int);
+ if (ret != ARRAY_SIZE(pcf_int)) {
+ dev_err(pcf->dev, "Error reading INT registers\n");
+
+ /*
+ * If this doesn't ACK the interrupt to the chip, we'll be
+ * called once again as we're level triggered.
+ */
+ goto out;
+ }
+
+ /* We immediately read the usb and adapter status. We thus make sure
+ * only of USBINS/USBREM IRQ handlers are called */
+ if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) {
+ chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
+ if (chgstat & (0x3 << 4))
+ pcf_int[0] &= ~(1 << PCF50633_INT1_USBREM);
+ else
+ pcf_int[0] &= ~(1 << PCF50633_INT1_USBINS);
+ }
+
+ /* Make sure only one of ADPINS or ADPREM is set */
+ if (pcf_int[0] & (PCF50633_INT1_ADPINS | PCF50633_INT1_ADPREM)) {
+ chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
+ if (chgstat & (0x3 << 4))
+ pcf_int[0] &= ~(1 << PCF50633_INT1_ADPREM);
+ else
+ pcf_int[0] &= ~(1 << PCF50633_INT1_ADPINS);
+ }
+
+ dev_dbg(pcf->dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x "
+ "INT4=0x%02x INT5=0x%02x\n", pcf_int[0],
+ pcf_int[1], pcf_int[2], pcf_int[3], pcf_int[4]);
+
+ /* Some revisions of the chip don't have a 8s standby mode on
+ * ONKEY1S press. We try to manually do it in such cases. */
+ if ((pcf_int[0] & PCF50633_INT1_SECOND) && pcf->onkey1s_held) {
+ dev_info(pcf->dev, "ONKEY1S held for %d secs\n",
+ pcf->onkey1s_held);
+ if (pcf->onkey1s_held++ == PCF50633_ONKEY1S_TIMEOUT)
+ if (pcf->pdata->force_shutdown)
+ pcf->pdata->force_shutdown(pcf);
+ }
+
+ if (pcf_int[2] & PCF50633_INT3_ONKEY1S) {
+ dev_info(pcf->dev, "ONKEY1S held\n");
+ pcf->onkey1s_held = 1 ;
+
+ /* Unmask IRQ_SECOND */
+ pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT1M,
+ PCF50633_INT1_SECOND);
+
+ /* Unmask IRQ_ONKEYR */
+ pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT2M,
+ PCF50633_INT2_ONKEYR);
+ }
+
+ if ((pcf_int[1] & PCF50633_INT2_ONKEYR) && pcf->onkey1s_held) {
+ pcf->onkey1s_held = 0;
+
+ /* Mask SECOND and ONKEYR interrupts */
+ if (pcf->mask_regs[0] & PCF50633_INT1_SECOND)
+ pcf50633_reg_set_bit_mask(pcf,
+ PCF50633_REG_INT1M,
+ PCF50633_INT1_SECOND,
+ PCF50633_INT1_SECOND);
+
+ if (pcf->mask_regs[1] & PCF50633_INT2_ONKEYR)
+ pcf50633_reg_set_bit_mask(pcf,
+ PCF50633_REG_INT2M,
+ PCF50633_INT2_ONKEYR,
+ PCF50633_INT2_ONKEYR);
+ }
+
+ /* Have we just resumed ? */
+ if (pcf->is_suspended) {
+ pcf->is_suspended = 0;
+
+ /* Set the resume reason filtering out non resumers */
+ for (i = 0; i < ARRAY_SIZE(pcf_int); i++)
+ pcf->resume_reason[i] = pcf_int[i] &
+ pcf->pdata->resumers[i];
+
+ /* Make sure we don't pass on any ONKEY events to
+ * userspace now */
+ pcf_int[1] &= ~(PCF50633_INT2_ONKEYR | PCF50633_INT2_ONKEYF);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pcf_int); i++) {
+ /* Unset masked interrupts */
+ pcf_int[i] &= ~pcf->mask_regs[i];
+
+ for (j = 0; j < 8 ; j++)
+ if (pcf_int[i] & (1 << j))
+ pcf50633_irq_call_handler(pcf, (i * 8) + j);
+ }
+
+out:
+ put_device(pcf->dev);
+ enable_irq(pcf->irq);
+}
+
+static irqreturn_t pcf50633_irq(int irq, void *data)
+{
+ struct pcf50633 *pcf = data;
+
+ dev_dbg(pcf->dev, "pcf50633_irq\n");
+
+ get_device(pcf->dev);
+ disable_irq(pcf->irq);
+ schedule_work(&pcf->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+static void
+pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
+ struct platform_device **pdev)
+{
+ struct pcf50633_subdev_pdata *subdev_pdata;
+ int ret;
+
+ *pdev = platform_device_alloc(name, -1);
+ if (!*pdev) {
+ dev_err(pcf->dev, "Falied to allocate %s\n", name);
+ return;
+ }
+
+ subdev_pdata = kmalloc(sizeof(*subdev_pdata), GFP_KERNEL);
+ if (!subdev_pdata) {
+ dev_err(pcf->dev, "Error allocating subdev pdata\n");
+ platform_device_put(*pdev);
+ }
+
+ subdev_pdata->pcf = pcf;
+ platform_device_add_data(*pdev, subdev_pdata, sizeof(*subdev_pdata));
+
+ (*pdev)->dev.parent = pcf->dev;
+
+ ret = platform_device_add(*pdev);
+ if (ret) {
+ dev_err(pcf->dev, "Failed to register %s: %d\n", name, ret);
+ platform_device_put(*pdev);
+ *pdev = NULL;
+ }
+}
+
+#ifdef CONFIG_PM
+static int pcf50633_suspend(struct device *dev, pm_message_t state)
+{
+ struct pcf50633 *pcf;
+ int ret = 0, i;
+ u8 res[5];
+
+ pcf = dev_get_drvdata(dev);
+
+ /* Make sure our interrupt handlers are not called
+ * henceforth */
+ disable_irq(pcf->irq);
+
+ /* Make sure that any running IRQ worker has quit */
+ cancel_work_sync(&pcf->irq_work);
+
+ /* Save the masks */
+ ret = pcf50633_read_block(pcf, PCF50633_REG_INT1M,
+ ARRAY_SIZE(pcf->suspend_irq_masks),
+ pcf->suspend_irq_masks);
+ if (ret < 0) {
+ dev_err(pcf->dev, "error saving irq masks\n");
+ goto out;
+ }
+
+ /* Write wakeup irq masks */
+ for (i = 0; i < ARRAY_SIZE(res); i++)
+ res[i] = ~pcf->pdata->resumers[i];
+
+ ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
+ ARRAY_SIZE(res), &res[0]);
+ if (ret < 0) {
+ dev_err(pcf->dev, "error writing wakeup irq masks\n");
+ goto out;
+ }
+
+ pcf->is_suspended = 1;
+
+out:
+ return ret;
+}
+
+static int pcf50633_resume(struct device *dev)
+{
+ struct pcf50633 *pcf;
+ int ret;
+
+ pcf = dev_get_drvdata(dev);
+
+ /* Write the saved mask registers */
+ ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
+ ARRAY_SIZE(pcf->suspend_irq_masks),
+ pcf->suspend_irq_masks);
+ if (ret < 0)
+ dev_err(pcf->dev, "Error restoring saved suspend masks\n");
+
+ /* Restore regulators' state */
+
+
+ get_device(pcf->dev);
+
+ /*
+ * Clear any pending interrupts and set resume reason if any.
+ * This will leave with enable_irq()
+ */
+ pcf50633_irq_worker(&pcf->irq_work);
+
+ return 0;
+}
+#else
+#define pcf50633_suspend NULL
+#define pcf50633_resume NULL
+#endif
+
+static int __devinit pcf50633_probe(struct i2c_client *client,
+ const struct i2c_device_id *ids)
+{
+ struct pcf50633 *pcf;
+ struct pcf50633_platform_data *pdata = client->dev.platform_data;
+ int i, ret = 0;
+ int version, variant;
+
+ pcf = kzalloc(sizeof(*pcf), GFP_KERNEL);
+ if (!pcf)
+ return -ENOMEM;
+
+ pcf->pdata = pdata;
+
+ mutex_init(&pcf->lock);
+
+ i2c_set_clientdata(client, pcf);
+ pcf->dev = &client->dev;
+ pcf->i2c_client = client;
+ pcf->irq = client->irq;
+
+ INIT_WORK(&pcf->irq_work, pcf50633_irq_worker);
+
+ version = pcf50633_reg_read(pcf, 0);
+ variant = pcf50633_reg_read(pcf, 1);
+ if (version < 0 || variant < 0) {
+ dev_err(pcf->dev, "Unable to probe pcf50633\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ dev_info(pcf->dev, "Probed device version %d variant %d\n",
+ version, variant);
+
+ /* Enable all interrupts except RTC SECOND */
+ pcf->mask_regs[0] = 0x80;
+ pcf50633_reg_write(pcf, PCF50633_REG_INT1M, pcf->mask_regs[0]);
+ pcf50633_reg_write(pcf, PCF50633_REG_INT2M, 0x00);
+ pcf50633_reg_write(pcf, PCF50633_REG_INT3M, 0x00);
+ pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00);
+ pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00);
+
+ /* Create sub devices */
+ pcf50633_client_dev_register(pcf, "pcf50633-input",
+ &pcf->input_pdev);
+ pcf50633_client_dev_register(pcf, "pcf50633-rtc",
+ &pcf->rtc_pdev);
+ pcf50633_client_dev_register(pcf, "pcf50633-mbc",
+ &pcf->mbc_pdev);
+ pcf50633_client_dev_register(pcf, "pcf50633-adc",
+ &pcf->adc_pdev);
+
+ for (i = 0; i < PCF50633_NUM_REGULATORS; i++) {
+ struct platform_device *pdev;
+
+ pdev = platform_device_alloc("pcf50633-regltr", i);
+ if (!pdev) {
+ dev_err(pcf->dev, "Cannot create regulator\n");
+ continue;
+ }
+
+ pdev->dev.parent = pcf->dev;
+ pdev->dev.platform_data = &pdata->reg_init_data[i];
+ pdev->dev.driver_data = pcf;
+ pcf->regulator_pdev[i] = pdev;
+
+ platform_device_add(pdev);
+ }
+
+ if (client->irq) {
+ set_irq_handler(client->irq, handle_level_irq);
+ ret = request_irq(client->irq, pcf50633_irq,
+ IRQF_TRIGGER_LOW, "pcf50633", pcf);
+
+ if (ret) {
+ dev_err(pcf->dev, "Failed to request IRQ %d\n", ret);
+ goto err;
+ }
+ } else {
+ dev_err(pcf->dev, "No IRQ configured\n");
+ goto err;
+ }
+
+ if (enable_irq_wake(client->irq) < 0)
+ dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source"
+ "in this hardware revision", client->irq);
+
+ ret = sysfs_create_group(&client->dev.kobj, &pcf_attr_group);
+ if (ret)
+ dev_err(pcf->dev, "error creating sysfs entries\n");
+
+ if (pdata->probe_done)
+ pdata->probe_done(pcf);
+
+ return 0;
+
+err:
+ kfree(pcf);
+ return ret;
+}
+
+static int __devexit pcf50633_remove(struct i2c_client *client)
+{
+ struct pcf50633 *pcf = i2c_get_clientdata(client);
+ int i;
+
+ free_irq(pcf->irq, pcf);
+
+ platform_device_unregister(pcf->input_pdev);
+ platform_device_unregister(pcf->rtc_pdev);
+ platform_device_unregister(pcf->mbc_pdev);
+ platform_device_unregister(pcf->adc_pdev);
+
+ for (i = 0; i < PCF50633_NUM_REGULATORS; i++)
+ platform_device_unregister(pcf->regulator_pdev[i]);
+
+ kfree(pcf);
+
+ return 0;
+}
+
+static struct i2c_device_id pcf50633_id_table[] = {
+ {"pcf50633", 0x73},
+};
+
+static struct i2c_driver pcf50633_driver = {
+ .driver = {
+ .name = "pcf50633",
+ .suspend = pcf50633_suspend,
+ .resume = pcf50633_resume,
+ },
+ .id_table = pcf50633_id_table,
+ .probe = pcf50633_probe,
+ .remove = __devexit_p(pcf50633_remove),
+};
+
+static int __init pcf50633_init(void)
+{
+ return i2c_add_driver(&pcf50633_driver);
+}
+
+static void __exit pcf50633_exit(void)
+{
+ i2c_del_driver(&pcf50633_driver);
+}
+
+MODULE_DESCRIPTION("I2C chip driver for NXP PCF50633 PMU");
+MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
+MODULE_LICENSE("GPL");
+
+module_init(pcf50633_init);
+module_exit(pcf50633_exit);
diff --git a/drivers/mfd/pcf50633-gpio.c b/drivers/mfd/pcf50633-gpio.c
new file mode 100644
index 000000000000..2fa2eca5c9cc
--- /dev/null
+++ b/drivers/mfd/pcf50633-gpio.c
@@ -0,0 +1,118 @@
+/* NXP PCF50633 GPIO Driver
+ *
+ * (C) 2006-2008 by Openmoko, Inc.
+ * Author: Balaji Rao <balajirrao@openmoko.org>
+ * All rights reserved.
+ *
+ * Broken down from monstrous PCF50633 driver mainly by
+ * Harald Welte, Andy Green and Werner Almesberger
+ *
+ * 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/kernel.h>
+
+#include <linux/mfd/pcf50633/core.h>
+#include <linux/mfd/pcf50633/gpio.h>
+
+enum pcf50633_regulator_id {
+ PCF50633_REGULATOR_AUTO,
+ PCF50633_REGULATOR_DOWN1,
+ PCF50633_REGULATOR_DOWN2,
+ PCF50633_REGULATOR_LDO1,
+ PCF50633_REGULATOR_LDO2,
+ PCF50633_REGULATOR_LDO3,
+ PCF50633_REGULATOR_LDO4,
+ PCF50633_REGULATOR_LDO5,
+ PCF50633_REGULATOR_LDO6,
+ PCF50633_REGULATOR_HCLDO,
+ PCF50633_REGULATOR_MEMLDO,
+};
+
+#define PCF50633_REG_AUTOOUT 0x1a
+#define PCF50633_REG_DOWN1OUT 0x1e
+#define PCF50633_REG_DOWN2OUT 0x22
+#define PCF50633_REG_MEMLDOOUT 0x26
+#define PCF50633_REG_LDO1OUT 0x2d
+#define PCF50633_REG_LDO2OUT 0x2f
+#define PCF50633_REG_LDO3OUT 0x31
+#define PCF50633_REG_LDO4OUT 0x33
+#define PCF50633_REG_LDO5OUT 0x35
+#define PCF50633_REG_LDO6OUT 0x37
+#define PCF50633_REG_HCLDOOUT 0x39
+
+static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
+ [PCF50633_REGULATOR_AUTO] = PCF50633_REG_AUTOOUT,
+ [PCF50633_REGULATOR_DOWN1] = PCF50633_REG_DOWN1OUT,
+ [PCF50633_REGULATOR_DOWN2] = PCF50633_REG_DOWN2OUT,
+ [PCF50633_REGULATOR_MEMLDO] = PCF50633_REG_MEMLDOOUT,
+ [PCF50633_REGULATOR_LDO1] = PCF50633_REG_LDO1OUT,
+ [PCF50633_REGULATOR_LDO2] = PCF50633_REG_LDO2OUT,
+ [PCF50633_REGULATOR_LDO3] = PCF50633_REG_LDO3OUT,
+ [PCF50633_REGULATOR_LDO4] = PCF50633_REG_LDO4OUT,
+ [PCF50633_REGULATOR_LDO5] = PCF50633_REG_LDO5OUT,
+ [PCF50633_REGULATOR_LDO6] = PCF50633_REG_LDO6OUT,
+ [PCF50633_REGULATOR_HCLDO] = PCF50633_REG_HCLDOOUT,
+};
+
+int pcf50633_gpio_set(struct pcf50633 *pcf, int gpio, u8 val)
+{
+ u8 reg;
+
+ reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG;
+
+ return pcf50633_reg_set_bit_mask(pcf, reg, 0x07, val);
+}
+EXPORT_SYMBOL_GPL(pcf50633_gpio_set);
+
+u8 pcf50633_gpio_get(struct pcf50633 *pcf, int gpio)
+{
+ u8 reg, val;
+
+ reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG;
+ val = pcf50633_reg_read(pcf, reg) & 0x07;
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(pcf50633_gpio_get);
+
+int pcf50633_gpio_invert_set(struct pcf50633 *pcf, int gpio, int invert)
+{
+ u8 val, reg;
+
+ reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG;
+ val = !!invert << 3;
+
+ return pcf50633_reg_set_bit_mask(pcf, reg, 1 << 3, val);
+}
+EXPORT_SYMBOL_GPL(pcf50633_gpio_invert_set);
+
+int pcf50633_gpio_invert_get(struct pcf50633 *pcf, int gpio)
+{
+ u8 reg, val;
+
+ reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG;
+ val = pcf50633_reg_read(pcf, reg);
+
+ return val & (1 << 3);
+}
+EXPORT_SYMBOL_GPL(pcf50633_gpio_invert_get);
+
+int pcf50633_gpio_power_supply_set(struct pcf50633 *pcf,
+ int gpio, int regulator, int on)
+{
+ u8 reg, val, mask;
+
+ /* the *ENA register is always one after the *OUT register */
+ reg = pcf50633_regulator_registers[regulator] + 1;
+
+ val = !!on << (gpio - PCF50633_GPIO1);
+ mask = 1 << (gpio - PCF50633_GPIO1);
+
+ return pcf50633_reg_set_bit_mask(pcf, reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(pcf50633_gpio_power_supply_set);
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 170f9d47c2f9..0e5761f12634 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -41,6 +41,7 @@ struct sm501_gpio_chip {
struct gpio_chip gpio;
struct sm501_gpio *ourgpio; /* to get back to parent. */
void __iomem *regbase;
+ void __iomem *control; /* address of control reg. */
};
struct sm501_gpio {
@@ -908,6 +909,25 @@ static int sm501_gpio_get(struct gpio_chip *chip, unsigned offset)
return result & 1UL;
}
+static void sm501_gpio_ensure_gpio(struct sm501_gpio_chip *smchip,
+ unsigned long bit)
+{
+ unsigned long ctrl;
+
+ /* check and modify if this pin is not set as gpio. */
+
+ if (readl(smchip->control) & bit) {
+ dev_info(sm501_gpio_to_dev(smchip->ourgpio)->dev,
+ "changing mode of gpio, bit %08lx\n", bit);
+
+ ctrl = readl(smchip->control);
+ ctrl &= ~bit;
+ writel(ctrl, smchip->control);
+
+ sm501_sync_regs(sm501_gpio_to_dev(smchip->ourgpio));
+ }
+}
+
static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
@@ -929,6 +949,8 @@ static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
writel(val, regs);
sm501_sync_regs(sm501_gpio_to_dev(smgpio));
+ sm501_gpio_ensure_gpio(smchip, bit);
+
spin_unlock_irqrestore(&smgpio->lock, save);
}
@@ -941,8 +963,8 @@ static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset)
unsigned long save;
unsigned long ddr;
- dev_info(sm501_gpio_to_dev(smgpio)->dev, "%s(%p,%d)\n",
- __func__, chip, offset);
+ dev_dbg(sm501_gpio_to_dev(smgpio)->dev, "%s(%p,%d)\n",
+ __func__, chip, offset);
spin_lock_irqsave(&smgpio->lock, save);
@@ -950,6 +972,8 @@ static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset)
writel(ddr & ~bit, regs + SM501_GPIO_DDR_LOW);
sm501_sync_regs(sm501_gpio_to_dev(smgpio));
+ sm501_gpio_ensure_gpio(smchip, bit);
+
spin_unlock_irqrestore(&smgpio->lock, save);
return 0;
@@ -1012,9 +1036,11 @@ static int __devinit sm501_gpio_register_chip(struct sm501_devdata *sm,
if (base > 0)
base += 32;
chip->regbase = gpio->regs + SM501_GPIO_DATA_HIGH;
+ chip->control = sm->regs + SM501_GPIO63_32_CONTROL;
gchip->label = "SM501-HIGH";
} else {
chip->regbase = gpio->regs + SM501_GPIO_DATA_LOW;
+ chip->control = sm->regs + SM501_GPIO31_0_CONTROL;
gchip->label = "SM501-LOW";
}
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c
index b59c385cbc12..e7ab0035d305 100644
--- a/drivers/mfd/twl4030-core.c
+++ b/drivers/mfd/twl4030-core.c
@@ -38,6 +38,9 @@
#include <linux/i2c.h>
#include <linux/i2c/twl4030.h>
+#ifdef CONFIG_ARM
+#include <mach/cpu.h>
+#endif
/*
* The TWL4030 "Triton 2" is one of a family of a multi-function "Power
@@ -646,7 +649,7 @@ static inline int __init unprotect_pm_master(void)
return e;
}
-static void __init clocks_init(void)
+static void __init clocks_init(struct device *dev)
{
int e = 0;
struct clk *osc;
@@ -655,9 +658,9 @@ static void __init clocks_init(void)
#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
if (cpu_is_omap2430())
- osc = clk_get(NULL, "osc_ck");
+ osc = clk_get(dev, "osc_ck");
else
- osc = clk_get(NULL, "osc_sys_ck");
+ osc = clk_get(dev, "osc_sys_ck");
if (IS_ERR(osc)) {
printk(KERN_WARNING "Skipping twl4030 internal clock init and "
@@ -773,7 +776,7 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
inuse = true;
/* setup clock framework */
- clocks_init();
+ clocks_init(&client->dev);
/* Maybe init the T2 Interrupt subsystem */
if (client->irq
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
index 3a273ccef3f2..f92595c8f165 100644
--- a/drivers/mfd/wm8350-core.c
+++ b/drivers/mfd/wm8350-core.c
@@ -1453,6 +1453,9 @@ void wm8350_device_exit(struct wm8350 *wm8350)
{
int i;
+ for (i = 0; i < ARRAY_SIZE(wm8350->pmic.led); i++)
+ platform_device_unregister(wm8350->pmic.led[i].pdev);
+
for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++)
platform_device_unregister(wm8350->pmic.pdev[i]);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index fee7304102af..419c378bd24b 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -120,7 +120,7 @@ config TIFM_CORE
cards are supported via 'MMC/SD Card support: TI Flash Media MMC/SD
Interface support (MMC_TIFM_SD)'.
- To compile this driver as a module, choose M here: the module will
+ To compile this driver as a module, choose M here: the module will
be called tifm_core.
config TIFM_7XX1
@@ -133,100 +133,9 @@ config TIFM_7XX1
To make actual use of the device, you will have to select some
flash card format drivers, as outlined in the TIFM_CORE Help.
- To compile this driver as a module, choose M here: the module will
+ To compile this driver as a module, choose M here: the module will
be called tifm_7xx1.
-config ACER_WMI
- tristate "Acer WMI Laptop Extras (EXPERIMENTAL)"
- depends on X86
- depends on EXPERIMENTAL
- depends on ACPI
- depends on LEDS_CLASS
- depends on NEW_LEDS
- depends on BACKLIGHT_CLASS_DEVICE
- depends on SERIO_I8042
- depends on RFKILL
- select ACPI_WMI
- ---help---
- This is a driver for newer Acer (and Wistron) laptops. It adds
- wireless radio and bluetooth control, and on some laptops,
- exposes the mail LED and LCD backlight.
-
- For more information about this driver see
- <file:Documentation/laptops/acer-wmi.txt>
-
- If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
- here.
-
-config ASUS_LAPTOP
- tristate "Asus Laptop Extras (EXPERIMENTAL)"
- depends on X86
- depends on ACPI
- depends on EXPERIMENTAL && !ACPI_ASUS
- depends on LEDS_CLASS
- depends on NEW_LEDS
- depends on BACKLIGHT_CLASS_DEVICE
- ---help---
- This is the new Linux driver for Asus laptops. It may also support some
- MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
- standard ACPI events that go through /proc/acpi/events. It also adds
- support for video output switching, LCD backlight control, Bluetooth and
- Wlan control, and most importantly, allows you to blink those fancy LEDs.
-
- For more information and a userspace daemon for handling the extra
- buttons see <http://acpi4asus.sf.net/>.
-
- If you have an ACPI-compatible ASUS laptop, say Y or M here.
-
-config FUJITSU_LAPTOP
- tristate "Fujitsu Laptop Extras"
- depends on X86
- depends on ACPI
- depends on INPUT
- depends on BACKLIGHT_CLASS_DEVICE
- ---help---
- This is a driver for laptops built by Fujitsu:
-
- * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks
- * Possibly other Fujitsu laptop models
- * Tested with S6410 and S7020
-
- It adds support for LCD brightness control and some hotkeys.
-
- If you have a Fujitsu laptop, say Y or M here.
-
-config FUJITSU_LAPTOP_DEBUG
- bool "Verbose debug mode for Fujitsu Laptop Extras"
- depends on FUJITSU_LAPTOP
- default n
- ---help---
- Enables extra debug output from the fujitsu extras driver, at the
- expense of a slight increase in driver size.
-
- If you are not sure, say N here.
-
-config TC1100_WMI
- tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)"
- depends on X86 && !X86_64
- depends on EXPERIMENTAL
- depends on ACPI
- select ACPI_WMI
- ---help---
- This is a driver for the WMI extensions (wireless and bluetooth power
- control) of the HP Compaq TC1100 tablet.
-
-config HP_WMI
- tristate "HP WMI extras"
- depends on ACPI_WMI
- depends on INPUT
- depends on RFKILL
- help
- Say Y here if you want to support WMI-based hotkeys on HP laptops and
- to read data from WMI such as docking or ambient light sensor state.
-
- To compile this driver as a module, choose M here: the module will
- be called hp-wmi.
-
config ICS932S401
tristate "Integrated Circuits ICS932S401"
depends on I2C && EXPERIMENTAL
@@ -237,170 +146,6 @@ config ICS932S401
This driver can also be built as a module. If so, the module
will be called ics932s401.
-config MSI_LAPTOP
- tristate "MSI Laptop Extras"
- depends on X86
- depends on ACPI
- depends on BACKLIGHT_CLASS_DEVICE
- ---help---
- This is a driver for laptops built by MSI (MICRO-STAR
- INTERNATIONAL):
-
- MSI MegaBook S270 (MS-1013)
- Cytron/TCM/Medion/Tchibo MD96100/SAM2000
-
- It adds support for Bluetooth, WLAN and LCD brightness control.
-
- More information about this driver is available at
- <http://0pointer.de/lennart/tchibo.html>.
-
- If you have an MSI S270 laptop, say Y or M here.
-
-config PANASONIC_LAPTOP
- tristate "Panasonic Laptop Extras"
- depends on X86 && INPUT && ACPI
- depends on BACKLIGHT_CLASS_DEVICE
- ---help---
- This driver adds support for access to backlight control and hotkeys
- on Panasonic Let's Note laptops.
-
- If you have a Panasonic Let's note laptop (such as the R1(N variant),
- R2, R3, R5, T2, W2 and Y2 series), say Y.
-
-config COMPAL_LAPTOP
- tristate "Compal Laptop Extras"
- depends on X86
- depends on ACPI
- depends on BACKLIGHT_CLASS_DEVICE
- ---help---
- This is a driver for laptops built by Compal:
-
- Compal FL90/IFL90
- Compal FL91/IFL91
- Compal FL92/JFL92
- Compal FT00/IFT00
-
- It adds support for Bluetooth, WLAN and LCD brightness control.
-
- If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here.
-
-config SONY_LAPTOP
- tristate "Sony Laptop Extras"
- depends on X86 && ACPI
- select BACKLIGHT_CLASS_DEVICE
- depends on INPUT
- ---help---
- This mini-driver drives the SNC and SPIC devices present in the ACPI
- BIOS of the Sony Vaio laptops.
-
- It gives access to some extra laptop functionalities like Bluetooth,
- screen brightness control, Fn keys and allows powering on/off some
- devices.
-
- Read <file:Documentation/laptops/sony-laptop.txt> for more information.
-
-config SONYPI_COMPAT
- bool "Sonypi compatibility"
- depends on SONY_LAPTOP
- ---help---
- Build the sonypi driver compatibility code into the sony-laptop driver.
-
-config THINKPAD_ACPI
- tristate "ThinkPad ACPI Laptop Extras"
- depends on X86 && ACPI
- select BACKLIGHT_LCD_SUPPORT
- select BACKLIGHT_CLASS_DEVICE
- select HWMON
- select NVRAM
- select INPUT
- select NEW_LEDS
- select LEDS_CLASS
- select NET
- select RFKILL
- ---help---
- This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
- support for Fn-Fx key combinations, Bluetooth control, video
- output switching, ThinkLight control, UltraBay eject and more.
- For more information about this driver see
- <file:Documentation/laptops/thinkpad-acpi.txt> and
- <http://ibm-acpi.sf.net/> .
-
- This driver was formerly known as ibm-acpi.
-
- If you have an IBM or Lenovo ThinkPad laptop, say Y or M here.
-
-config THINKPAD_ACPI_DEBUG
- bool "Verbose debug mode"
- depends on THINKPAD_ACPI
- default n
- ---help---
- Enables extra debugging information, at the expense of a slightly
- increase in driver size.
-
- If you are not sure, say N here.
-
-config THINKPAD_ACPI_DOCK
- bool "Legacy Docking Station Support"
- depends on THINKPAD_ACPI
- depends on ACPI_DOCK=n
- default n
- ---help---
- Allows the thinkpad_acpi driver to handle docking station events.
- This support was made obsolete by the generic ACPI docking station
- support (CONFIG_ACPI_DOCK). It will allow locking and removing the
- laptop from the docking station, but will not properly connect PCI
- devices.
-
- If you are not sure, say N here.
-
-config THINKPAD_ACPI_BAY
- bool "Legacy Removable Bay Support"
- depends on THINKPAD_ACPI
- default y
- ---help---
- Allows the thinkpad_acpi driver to handle removable bays. It will
- electrically disable the device in the bay, and also generate
- notifications when the bay lever is ejected or inserted.
-
- If you are not sure, say Y here.
-
-config THINKPAD_ACPI_VIDEO
- bool "Video output control support"
- depends on THINKPAD_ACPI
- default y
- ---help---
- Allows the thinkpad_acpi driver to provide an interface to control
- the various video output ports.
-
- This feature often won't work well, depending on ThinkPad model,
- display state, video output devices in use, whether there is a X
- server running, phase of the moon, and the current mood of
- Schroedinger's cat. If you can use X.org's RandR to control
- your ThinkPad's video output ports instead of this feature,
- don't think twice: do it and say N here to save some memory.
-
- If you are not sure, say Y here.
-
-config THINKPAD_ACPI_HOTKEY_POLL
- bool "Support NVRAM polling for hot keys"
- depends on THINKPAD_ACPI
- default y
- ---help---
- Some thinkpad models benefit from NVRAM polling to detect a few of
- the hot key press events. If you know your ThinkPad model does not
- need to do NVRAM polling to support any of the hot keys you use,
- unselecting this option will save about 1kB of memory.
-
- ThinkPads T40 and newer, R52 and newer, and X31 and newer are
- unlikely to need NVRAM polling in their latest BIOS versions.
-
- NVRAM polling can detect at most the following keys: ThinkPad/Access
- IBM, Zoom, Switch Display (fn+F7), ThinkLight, Volume up/down/mute,
- Brightness up/down, Display Expand (fn+F8), Hibernate (fn+F12).
-
- If you are not sure, say Y here. The driver enables polling only if
- it is strictly necessary to do so.
-
config ATMEL_SSC
tristate "Device driver for Atmel SSC peripheral"
depends on AVR32 || ARCH_AT91
@@ -413,31 +158,6 @@ config ATMEL_SSC
If unsure, say N.
-config INTEL_MENLOW
- tristate "Thermal Management driver for Intel menlow platform"
- depends on ACPI_THERMAL
- select THERMAL
- depends on X86
- ---help---
- ACPI thermal management enhancement driver on
- Intel Menlow platform.
-
- If unsure, say N.
-
-config EEEPC_LAPTOP
- tristate "Eee PC Hotkey Driver (EXPERIMENTAL)"
- depends on X86
- depends on ACPI
- depends on BACKLIGHT_CLASS_DEVICE
- depends on HWMON
- depends on EXPERIMENTAL
- depends on RFKILL
- ---help---
- This driver supports the Fn-Fx keys on Eee PC laptops.
- It also adds the ability to switch camera/wlan on/off.
-
- If you have an Eee PC laptop, say Y or M here.
-
config ENCLOSURE_SERVICES
tristate "Enclosure Services"
default n
@@ -498,6 +218,18 @@ config SGI_GRU_DEBUG
This option enables addition debugging code for the SGI GRU driver. If
you are unsure, say N.
+config DELL_LAPTOP
+ tristate "Dell Laptop Extras (EXPERIMENTAL)"
+ depends on X86
+ depends on DCDBAS
+ depends on EXPERIMENTAL
+ depends on BACKLIGHT_CLASS_DEVICE
+ depends on RFKILL
+ default n
+ ---help---
+ This driver adds support for rfkill and backlight control to Dell
+ laptops.
+
source "drivers/misc/c2port/Kconfig"
endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 817f7f5ab3bd..d5749a7bc777 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -1,32 +1,19 @@
#
# Makefile for misc devices that really don't fit anywhere else.
#
-obj- := misc.o # Dummy rule to force built-in.o to be made
obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
-obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
-obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
-obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
-obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
-obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
-obj-$(CONFIG_HP_WMI) += hp-wmi.o
obj-$(CONFIG_ICS932S401) += ics932s401.o
-obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
obj-$(CONFIG_PHANTOM) += phantom.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
-obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
-obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
-obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
-obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
-obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
obj-$(CONFIG_SGI_XP) += sgi-xp/
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
index 0736cff9d97a..3cf61ece71d7 100644
--- a/drivers/misc/enclosure.c
+++ b/drivers/misc/enclosure.c
@@ -119,7 +119,7 @@ enclosure_register(struct device *dev, const char *name, int components,
edev->edev.class = &enclosure_class;
edev->edev.parent = get_device(dev);
edev->cb = cb;
- snprintf(edev->edev.bus_id, BUS_ID_SIZE, "%s", name);
+ dev_set_name(&edev->edev, name);
err = device_register(&edev->edev);
if (err)
goto err;
@@ -170,7 +170,7 @@ EXPORT_SYMBOL_GPL(enclosure_unregister);
static void enclosure_link_name(struct enclosure_component *cdev, char *name)
{
strcpy(name, "enclosure_device:");
- strcat(name, cdev->cdev.bus_id);
+ strcat(name, dev_name(&cdev->cdev));
}
static void enclosure_remove_links(struct enclosure_component *cdev)
@@ -256,9 +256,9 @@ enclosure_component_register(struct enclosure_device *edev,
cdev = &ecomp->cdev;
cdev->parent = get_device(&edev->edev);
if (name)
- snprintf(cdev->bus_id, BUS_ID_SIZE, "%s", name);
+ dev_set_name(cdev, name);
else
- snprintf(cdev->bus_id, BUS_ID_SIZE, "%u", number);
+ dev_set_name(cdev, "%u", number);
cdev->release = enclosure_component_release;
cdev->groups = enclosure_groups;
diff --git a/drivers/misc/ibmasm/event.c b/drivers/misc/ibmasm/event.c
index fda6a4d3bf23..68a0a5b94795 100644
--- a/drivers/misc/ibmasm/event.c
+++ b/drivers/misc/ibmasm/event.c
@@ -50,7 +50,7 @@ static void wake_up_event_readers(struct service_processor *sp)
* Store the event in the circular event buffer, wake up any sleeping
* event readers.
* There is no reader marker in the buffer, therefore readers are
- * responsible for keeping up with the writer, or they will loose events.
+ * responsible for keeping up with the writer, or they will lose events.
*/
void ibmasm_receive_event(struct service_processor *sp, void *data, unsigned int data_size)
{
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
index abdebe347383..fa57b67593ae 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -6,7 +6,7 @@
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * You need an userspace library to cooperate with this driver. It (and other
+ * You need a userspace library to cooperate with this driver. It (and other
* info) may be obtained here:
* http://www.fi.muni.cz/~xslaby/phantom.html
* or alternatively, you might use OpenHaptics provided by Sensable.
diff --git a/drivers/misc/sgi-xp/xpc_sn2.c b/drivers/misc/sgi-xp/xpc_sn2.c
index 73b7fb8de47a..82fb9958f22f 100644
--- a/drivers/misc/sgi-xp/xpc_sn2.c
+++ b/drivers/misc/sgi-xp/xpc_sn2.c
@@ -899,7 +899,7 @@ xpc_update_partition_info_sn2(struct xpc_partition *part, u8 remote_rp_version,
dev_dbg(xpc_part, " remote_vars_pa = 0x%016lx\n",
part_sn2->remote_vars_pa);
- part->last_heartbeat = remote_vars->heartbeat;
+ part->last_heartbeat = remote_vars->heartbeat - 1;
dev_dbg(xpc_part, " last_heartbeat = 0x%016lx\n",
part->last_heartbeat);
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c
index 81152b3e360c..7957f525b2f4 100644
--- a/drivers/misc/sgi-xp/xpnet.c
+++ b/drivers/misc/sgi-xp/xpnet.c
@@ -95,11 +95,6 @@ struct xpnet_pending_msg {
atomic_t use_count;
};
-/* driver specific structure pointed to by the device structure */
-struct xpnet_dev_private {
- struct net_device_stats stats;
-};
-
struct net_device *xpnet_device;
/*
@@ -153,7 +148,6 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg)
struct sk_buff *skb;
void *dst;
enum xp_retval ret;
- struct xpnet_dev_private *priv = netdev_priv(xpnet_device);
if (!XPNET_VALID_MSG(msg)) {
/*
@@ -161,7 +155,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg)
*/
xpc_received(partid, channel, (void *)msg);
- priv->stats.rx_errors++;
+ xpnet_device->stats.rx_errors++;
return;
}
@@ -176,7 +170,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg)
xpc_received(partid, channel, (void *)msg);
- priv->stats.rx_errors++;
+ xpnet_device->stats.rx_errors++;
return;
}
@@ -226,7 +220,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg)
xpc_received(partid, channel, (void *)msg);
- priv->stats.rx_errors++;
+ xpnet_device->stats.rx_errors++;
return;
}
@@ -247,8 +241,8 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg)
skb_end_pointer(skb), skb->len);
xpnet_device->last_rx = jiffies;
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += skb->len + ETH_HLEN;
+ xpnet_device->stats.rx_packets++;
+ xpnet_device->stats.rx_bytes += skb->len + ETH_HLEN;
netif_rx_ni(skb);
xpc_received(partid, channel, (void *)msg);
@@ -353,26 +347,6 @@ xpnet_dev_change_mtu(struct net_device *dev, int new_mtu)
}
/*
- * Required for the net_device structure.
- */
-static int
-xpnet_dev_set_config(struct net_device *dev, struct ifmap *new_map)
-{
- return 0;
-}
-
-/*
- * Return statistics to the caller.
- */
-static struct net_device_stats *
-xpnet_dev_get_stats(struct net_device *dev)
-{
- struct xpnet_dev_private *priv = netdev_priv(dev);
-
- return &priv->stats;
-}
-
-/*
* Notification that the other end has received the message and
* DMA'd the skb information. At this point, they are done with
* our side. When all recipients are done processing, we
@@ -453,7 +427,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct xpnet_pending_msg *queued_msg;
u64 start_addr, end_addr;
short dest_partid;
- struct xpnet_dev_private *priv = netdev_priv(dev);
u16 embedded_bytes = 0;
dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p "
@@ -476,7 +449,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_warn(xpnet, "failed to kmalloc %ld bytes; dropping "
"packet\n", sizeof(struct xpnet_pending_msg));
- priv->stats.tx_errors++;
+ dev->stats.tx_errors++;
return -ENOMEM;
}
@@ -526,8 +499,8 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
kfree(queued_msg);
}
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
return 0;
}
@@ -538,12 +511,19 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
static void
xpnet_dev_tx_timeout(struct net_device *dev)
{
- struct xpnet_dev_private *priv = netdev_priv(dev);
-
- priv->stats.tx_errors++;
- return;
+ dev->stats.tx_errors++;
}
+static const struct net_device_ops xpnet_netdev_ops = {
+ .ndo_open = xpnet_dev_open,
+ .ndo_stop = xpnet_dev_stop,
+ .ndo_start_xmit = xpnet_dev_hard_start_xmit,
+ .ndo_change_mtu = xpnet_dev_change_mtu,
+ .ndo_tx_timeout = xpnet_dev_tx_timeout,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
static int __init
xpnet_init(void)
{
@@ -563,8 +543,7 @@ xpnet_init(void)
* use ether_setup() to init the majority of our device
* structure and then override the necessary pieces.
*/
- xpnet_device = alloc_netdev(sizeof(struct xpnet_dev_private),
- XPNET_DEVICE_NAME, ether_setup);
+ xpnet_device = alloc_netdev(0, XPNET_DEVICE_NAME, ether_setup);
if (xpnet_device == NULL) {
kfree(xpnet_broadcast_partitions);
return -ENOMEM;
@@ -573,13 +552,6 @@ xpnet_init(void)
netif_carrier_off(xpnet_device);
xpnet_device->mtu = XPNET_DEF_MTU;
- xpnet_device->change_mtu = xpnet_dev_change_mtu;
- xpnet_device->open = xpnet_dev_open;
- xpnet_device->get_stats = xpnet_dev_get_stats;
- xpnet_device->stop = xpnet_dev_stop;
- xpnet_device->hard_start_xmit = xpnet_dev_hard_start_xmit;
- xpnet_device->tx_timeout = xpnet_dev_tx_timeout;
- xpnet_device->set_config = xpnet_dev_set_config;
/*
* Multicast assumes the LSB of the first octet is set for multicast
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 7a3f2436b011..76bfe16c09b1 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -25,8 +25,8 @@
#include <linux/stat.h>
#include <linux/mmc/host.h>
+#include <linux/atmel-mci.h>
-#include <asm/atmel-mci.h>
#include <asm/io.h>
#include <asm/unaligned.h>
@@ -55,7 +55,6 @@ enum atmel_mci_state {
struct atmel_mci_dma {
#ifdef CONFIG_MMC_ATMELMCI_DMA
- struct dma_client client;
struct dma_chan *chan;
struct dma_async_tx_descriptor *data_desc;
#endif
@@ -593,10 +592,8 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
/* If we don't have a channel, we can't do DMA */
chan = host->dma.chan;
- if (chan) {
- dma_chan_get(chan);
+ if (chan)
host->data_chan = chan;
- }
if (!chan)
return -ENODEV;
@@ -1443,60 +1440,6 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-#ifdef CONFIG_MMC_ATMELMCI_DMA
-
-static inline struct atmel_mci *
-dma_client_to_atmel_mci(struct dma_client *client)
-{
- return container_of(client, struct atmel_mci, dma.client);
-}
-
-static enum dma_state_client atmci_dma_event(struct dma_client *client,
- struct dma_chan *chan, enum dma_state state)
-{
- struct atmel_mci *host;
- enum dma_state_client ret = DMA_NAK;
-
- host = dma_client_to_atmel_mci(client);
-
- switch (state) {
- case DMA_RESOURCE_AVAILABLE:
- spin_lock_bh(&host->lock);
- if (!host->dma.chan) {
- host->dma.chan = chan;
- ret = DMA_ACK;
- }
- spin_unlock_bh(&host->lock);
-
- if (ret == DMA_ACK)
- dev_info(&host->pdev->dev,
- "Using %s for DMA transfers\n",
- chan->dev.bus_id);
- break;
-
- case DMA_RESOURCE_REMOVED:
- spin_lock_bh(&host->lock);
- if (host->dma.chan == chan) {
- host->dma.chan = NULL;
- ret = DMA_ACK;
- }
- spin_unlock_bh(&host->lock);
-
- if (ret == DMA_ACK)
- dev_info(&host->pdev->dev,
- "Lost %s, falling back to PIO\n",
- chan->dev.bus_id);
- break;
-
- default:
- break;
- }
-
-
- return ret;
-}
-#endif /* CONFIG_MMC_ATMELMCI_DMA */
-
static int __init atmci_init_slot(struct atmel_mci *host,
struct mci_slot_pdata *slot_data, unsigned int id,
u32 sdc_reg)
@@ -1600,6 +1543,18 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
mmc_free_host(slot->mmc);
}
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+static bool filter(struct dma_chan *chan, void *slave)
+{
+ struct dw_dma_slave *dws = slave;
+
+ if (dws->dma_dev == chan->device->dev)
+ return true;
+ else
+ return false;
+}
+#endif
+
static int __init atmci_probe(struct platform_device *pdev)
{
struct mci_platform_data *pdata;
@@ -1652,22 +1607,20 @@ static int __init atmci_probe(struct platform_device *pdev)
goto err_request_irq;
#ifdef CONFIG_MMC_ATMELMCI_DMA
- if (pdata->dma_slave) {
- struct dma_slave *slave = pdata->dma_slave;
+ if (pdata->dma_slave.dma_dev) {
+ struct dw_dma_slave *dws = &pdata->dma_slave;
+ dma_cap_mask_t mask;
- slave->tx_reg = regs->start + MCI_TDR;
- slave->rx_reg = regs->start + MCI_RDR;
+ dws->tx_reg = regs->start + MCI_TDR;
+ dws->rx_reg = regs->start + MCI_RDR;
/* Try to grab a DMA channel */
- host->dma.client.event_callback = atmci_dma_event;
- dma_cap_set(DMA_SLAVE, host->dma.client.cap_mask);
- host->dma.client.slave = slave;
-
- dma_async_client_register(&host->dma.client);
- dma_async_client_chan_request(&host->dma.client);
- } else {
- dev_notice(&pdev->dev, "DMA not available, using PIO\n");
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ host->dma.chan = dma_request_channel(mask, filter, dws);
}
+ if (!host->dma.chan)
+ dev_notice(&pdev->dev, "DMA not available, using PIO\n");
#endif /* CONFIG_MMC_ATMELMCI_DMA */
platform_set_drvdata(pdev, host);
@@ -1699,8 +1652,8 @@ static int __init atmci_probe(struct platform_device *pdev)
err_init_slot:
#ifdef CONFIG_MMC_ATMELMCI_DMA
- if (pdata->dma_slave)
- dma_async_client_unregister(&host->dma.client);
+ if (host->dma.chan)
+ dma_release_channel(host->dma.chan);
#endif
free_irq(irq, host);
err_request_irq:
@@ -1731,8 +1684,8 @@ static int __exit atmci_remove(struct platform_device *pdev)
clk_disable(host->mck);
#ifdef CONFIG_MMC_ATMELMCI_DMA
- if (host->dma.client.slave)
- dma_async_client_unregister(&host->dma.client);
+ if (host->dma.chan)
+ dma_release_channel(host->dma.chan);
#endif
free_irq(platform_get_irq(pdev, 0), host);
@@ -1761,7 +1714,7 @@ static void __exit atmci_exit(void)
platform_driver_unregister(&atmci_driver);
}
-module_init(atmci_init);
+late_initcall(atmci_init); /* try to load after dma driver when built-in */
module_exit(atmci_exit);
MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index a90d50c2c3e5..7d04fb9ddcaa 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -45,6 +45,14 @@ config MTD_PARTITIONS
devices. Partitioning on NFTL 'devices' is a different - that's the
'normal' form of partitioning used on a block device.
+config MTD_TESTS
+ tristate "MTD tests support"
+ depends on m
+ help
+ This option includes various MTD tests into compilation. The tests
+ should normally be compiled as kernel modules. The modules perform
+ various checks and verifications when loaded.
+
config MTD_REDBOOT_PARTS
tristate "RedBoot partition table parsing"
depends on MTD_PARTITIONS
@@ -316,6 +324,8 @@ source "drivers/mtd/nand/Kconfig"
source "drivers/mtd/onenand/Kconfig"
+source "drivers/mtd/lpddr/Kconfig"
+
source "drivers/mtd/ubi/Kconfig"
endif # MTD
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 4b77335715f0..4521b1ecce45 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -29,6 +29,6 @@ obj-$(CONFIG_MTD_OOPS) += mtdoops.o
nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o
-obj-y += chips/ maps/ devices/ nand/ onenand/
+obj-y += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/
obj-$(CONFIG_MTD_UBI) += ubi/
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index c93a8be5d5f1..f5ab6fa1057b 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -58,8 +58,8 @@ static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t
static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *);
static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
static void cfi_intelext_sync (struct mtd_info *);
-static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
-static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
#ifdef CONFIG_MTD_OTP
static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
@@ -558,8 +558,8 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
}
for (i=0; i<mtd->numeraseregions;i++){
- printk(KERN_DEBUG "erase region %d: offset=0x%x,size=0x%x,blocks=%d\n",
- i,mtd->eraseregions[i].offset,
+ printk(KERN_DEBUG "erase region %d: offset=0x%llx,size=0x%x,blocks=%d\n",
+ i,(unsigned long long)mtd->eraseregions[i].offset,
mtd->eraseregions[i].erasesize,
mtd->eraseregions[i].numblocks);
}
@@ -2058,7 +2058,7 @@ out: put_chip(map, chip, adr);
return ret;
}
-static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
int ret;
@@ -2082,7 +2082,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
return ret;
}
-static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
int ret;
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index d74ec46aa032..94bb61e19047 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -71,8 +71,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
#include "fwh_lock.h"
-static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
-static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
static struct mtd_chip_driver cfi_amdstd_chipdrv = {
.probe = NULL, /* Not usable directly */
@@ -322,6 +322,14 @@ static struct cfi_fixup fixup_table[] = {
};
+static void cfi_fixup_major_minor(struct cfi_private *cfi,
+ struct cfi_pri_amdstd *extp)
+{
+ if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e &&
+ extp->MajorVersion == '0')
+ extp->MajorVersion = '1';
+}
+
struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
{
struct cfi_private *cfi = map->fldrv_priv;
@@ -363,6 +371,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
return NULL;
}
+ cfi_fixup_major_minor(cfi, extp);
+
if (extp->MajorVersion != '1' ||
(extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query "
@@ -1774,12 +1784,12 @@ out_unlock:
return ret;
}
-static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
return cfi_varsize_frob(mtd, do_atmel_lock, ofs, len, NULL);
}
-static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
return cfi_varsize_frob(mtd, do_atmel_unlock, ofs, len, NULL);
}
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
index d4714dd9f7ab..6c740f346f91 100644
--- a/drivers/mtd/chips/cfi_cmdset_0020.c
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c
@@ -42,8 +42,8 @@ static int cfi_staa_writev(struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen);
static int cfi_staa_erase_varsize(struct mtd_info *, struct erase_info *);
static void cfi_staa_sync (struct mtd_info *);
-static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
-static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
static int cfi_staa_suspend (struct mtd_info *);
static void cfi_staa_resume (struct mtd_info *);
@@ -221,8 +221,8 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
}
for (i=0; i<mtd->numeraseregions;i++){
- printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
- i,mtd->eraseregions[i].offset,
+ printk(KERN_DEBUG "%d: offset=0x%llx,size=0x%x,blocks=%d\n",
+ i, (unsigned long long)mtd->eraseregions[i].offset,
mtd->eraseregions[i].erasesize,
mtd->eraseregions[i].numblocks);
}
@@ -964,7 +964,7 @@ static int cfi_staa_erase_varsize(struct mtd_info *mtd,
adr += regions[i].erasesize;
len -= regions[i].erasesize;
- if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
+ if (adr % (1<< cfi->chipshift) == (((unsigned long)regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
i++;
if (adr >> cfi->chipshift) {
@@ -1135,7 +1135,7 @@ retry:
spin_unlock_bh(chip->mutex);
return 0;
}
-static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -1284,7 +1284,7 @@ retry:
spin_unlock_bh(chip->mutex);
return 0;
}
-static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h
index ab44f2b996f8..57e0e4e921f9 100644
--- a/drivers/mtd/chips/fwh_lock.h
+++ b/drivers/mtd/chips/fwh_lock.h
@@ -77,7 +77,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
}
-static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
int ret;
@@ -88,7 +88,7 @@ static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len)
}
-static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
int ret;
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 6fde0a2e3567..bc33200535fc 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -120,6 +120,13 @@ config MTD_PHRAM
doesn't have access to, memory beyond the mem=xxx limit, nvram,
memory on the video card, etc...
+config MTD_PS3VRAM
+ tristate "PS3 video RAM"
+ depends on FB_PS3
+ help
+ This driver allows you to use excess PS3 video RAM as volatile
+ storage or system swap.
+
config MTD_LART
tristate "28F160xx flash driver for LART"
depends on SA1100_LART
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 0993d5cf3923..e51521df4e40 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_MTD_LART) += lart.o
obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
obj-$(CONFIG_MTD_M25P80) += m25p80.o
+obj-$(CONFIG_MTD_PS3VRAM) += ps3vram.o
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c
index f4bda4cee495..578de1c67bfe 100644
--- a/drivers/mtd/devices/lart.c
+++ b/drivers/mtd/devices/lart.c
@@ -619,7 +619,7 @@ static struct mtd_partition lart_partitions[] = {
};
#endif
-int __init lart_flash_init (void)
+static int __init lart_flash_init (void)
{
int result;
memset (&mtd,0,sizeof (mtd));
@@ -690,7 +690,7 @@ int __init lart_flash_init (void)
return (result);
}
-void __exit lart_flash_exit (void)
+static void __exit lart_flash_exit (void)
{
#ifndef HAVE_PARTITIONS
del_mtd_device (&mtd);
@@ -705,5 +705,3 @@ module_exit (lart_flash_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Abraham vd Merwe <abraham@2d3d.co.za>");
MODULE_DESCRIPTION("MTD driver for Intel 28F160F3 on LART board");
-
-
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 5733f0643843..7c3fc766dcf1 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -20,6 +20,7 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
+#include <linux/math64.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -169,9 +170,9 @@ static int wait_till_ready(struct m25p *flash)
*/
static int erase_chip(struct m25p *flash)
{
- DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB\n",
- dev_name(&flash->spi->dev), __func__,
- flash->mtd.size / 1024);
+ DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %lldKiB\n",
+ dev_name(&flash->spi->dev), __func__,
+ (long long)(flash->mtd.size >> 10));
/* Wait until finished previous write command. */
if (wait_till_ready(flash))
@@ -232,18 +233,18 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
{
struct m25p *flash = mtd_to_m25p(mtd);
u32 addr,len;
+ uint32_t rem;
- DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n",
- dev_name(&flash->spi->dev), __func__, "at",
- (u32)instr->addr, instr->len);
+ DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%llx, len %lld\n",
+ dev_name(&flash->spi->dev), __func__, "at",
+ (long long)instr->addr, (long long)instr->len);
/* sanity checks */
if (instr->addr + instr->len > flash->mtd.size)
return -EINVAL;
- if ((instr->addr % mtd->erasesize) != 0
- || (instr->len % mtd->erasesize) != 0) {
+ div_u64_rem(instr->len, mtd->erasesize, &rem);
+ if (rem)
return -EINVAL;
- }
addr = instr->addr;
len = instr->len;
@@ -677,24 +678,24 @@ static int __devinit m25p_probe(struct spi_device *spi)
flash->mtd.erasesize = info->sector_size;
}
- dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name,
- flash->mtd.size / 1024);
+ dev_info(&spi->dev, "%s (%lld Kbytes)\n", info->name,
+ (long long)flash->mtd.size >> 10);
DEBUG(MTD_DEBUG_LEVEL2,
- "mtd .name = %s, .size = 0x%.8x (%uMiB) "
+ "mtd .name = %s, .size = 0x%llx (%lldMiB) "
".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
flash->mtd.name,
- flash->mtd.size, flash->mtd.size / (1024*1024),
+ (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20),
flash->mtd.erasesize, flash->mtd.erasesize / 1024,
flash->mtd.numeraseregions);
if (flash->mtd.numeraseregions)
for (i = 0; i < flash->mtd.numeraseregions; i++)
DEBUG(MTD_DEBUG_LEVEL2,
- "mtd.eraseregions[%d] = { .offset = 0x%.8x, "
+ "mtd.eraseregions[%d] = { .offset = 0x%llx, "
".erasesize = 0x%.8x (%uKiB), "
".numblocks = %d }\n",
- i, flash->mtd.eraseregions[i].offset,
+ i, (long long)flash->mtd.eraseregions[i].offset,
flash->mtd.eraseregions[i].erasesize,
flash->mtd.eraseregions[i].erasesize / 1024,
flash->mtd.eraseregions[i].numblocks);
@@ -722,12 +723,12 @@ static int __devinit m25p_probe(struct spi_device *spi)
if (nr_parts > 0) {
for (i = 0; i < nr_parts; i++) {
DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
- "{.name = %s, .offset = 0x%.8x, "
- ".size = 0x%.8x (%uKiB) }\n",
+ "{.name = %s, .offset = 0x%llx, "
+ ".size = 0x%llx (%lldKiB) }\n",
i, parts[i].name,
- parts[i].offset,
- parts[i].size,
- parts[i].size / 1024);
+ (long long)parts[i].offset,
+ (long long)parts[i].size,
+ (long long)(parts[i].size >> 10));
}
flash->partitioned = 1;
return add_mtd_partitions(&flash->mtd, parts, nr_parts);
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index 65126cd668ff..d44f741ae229 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -16,6 +16,7 @@
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/err.h>
+#include <linux/math64.h>
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
@@ -152,15 +153,20 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
struct spi_message msg;
unsigned blocksize = priv->page_size << 3;
uint8_t *command;
+ uint32_t rem;
- DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%x len 0x%x\n",
- dev_name(&spi->dev),
- instr->addr, instr->len);
+ DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%llx len 0x%llx\n",
+ dev_name(&spi->dev), (long long)instr->addr,
+ (long long)instr->len);
/* Sanity checks */
- if ((instr->addr + instr->len) > mtd->size
- || (instr->len % priv->page_size) != 0
- || (instr->addr % priv->page_size) != 0)
+ if (instr->addr + instr->len > mtd->size)
+ return -EINVAL;
+ div_u64_rem(instr->len, priv->page_size, &rem);
+ if (rem)
+ return -EINVAL;
+ div_u64_rem(instr->addr, priv->page_size, &rem);
+ if (rem)
return -EINVAL;
spi_message_init(&msg);
@@ -178,7 +184,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
/* Calculate flash page address; use block erase (for speed) if
* we're at a block boundary and need to erase the whole block.
*/
- pageaddr = instr->addr / priv->page_size;
+ pageaddr = div_u64(instr->len, priv->page_size);
do_block = (pageaddr & 0x7) == 0 && instr->len >= blocksize;
pageaddr = pageaddr << priv->page_offset;
@@ -667,8 +673,8 @@ add_dataflash_otp(struct spi_device *spi, char *name,
if (revision >= 'c')
otp_tag = otp_setup(device, revision);
- dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes%s\n",
- name, DIV_ROUND_UP(device->size, 1024),
+ dev_info(&spi->dev, "%s (%lld KBytes) pagesize %d bytes%s\n",
+ name, (long long)((device->size + 1023) >> 10),
pagesize, otp_tag);
dev_set_drvdata(&spi->dev, priv);
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index d38bca64bb15..d2fd550f7e09 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -34,7 +34,7 @@
* aperture size, not the dram size, and the V370PDC supplies no
* other method for memory size discovery. This problem is
* mostly only relevant when compiled as a module, as the
- * unloading of the module with an aperture size smaller then
+ * unloading of the module with an aperture size smaller than
* the ram will cause the driver to detect the onboard memory
* size to be equal to the aperture size when the module is
* reloaded. Soooo, to help, the module supports an msize
diff --git a/drivers/mtd/devices/ps3vram.c b/drivers/mtd/devices/ps3vram.c
new file mode 100644
index 000000000000..d21e9beb7ed2
--- /dev/null
+++ b/drivers/mtd/devices/ps3vram.c
@@ -0,0 +1,768 @@
+/**
+ * ps3vram - Use extra PS3 video ram as MTD block device.
+ *
+ * Copyright (c) 2007-2008 Jim Paris <jim@jtan.com>
+ * Added support RSX DMA Vivien Chappelier <vivien.chappelier@free.fr>
+ */
+
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/gfp.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3.h>
+
+#define DEVICE_NAME "ps3vram"
+
+#define XDR_BUF_SIZE (2 * 1024 * 1024) /* XDR buffer (must be 1MiB aligned) */
+#define XDR_IOIF 0x0c000000
+
+#define FIFO_BASE XDR_IOIF
+#define FIFO_SIZE (64 * 1024)
+
+#define DMA_PAGE_SIZE (4 * 1024)
+
+#define CACHE_PAGE_SIZE (256 * 1024)
+#define CACHE_PAGE_COUNT ((XDR_BUF_SIZE - FIFO_SIZE) / CACHE_PAGE_SIZE)
+
+#define CACHE_OFFSET CACHE_PAGE_SIZE
+#define FIFO_OFFSET 0
+
+#define CTRL_PUT 0x10
+#define CTRL_GET 0x11
+#define CTRL_TOP 0x15
+
+#define UPLOAD_SUBCH 1
+#define DOWNLOAD_SUBCH 2
+
+#define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c
+#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104
+
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601
+
+struct mtd_info ps3vram_mtd;
+
+#define CACHE_PAGE_PRESENT 1
+#define CACHE_PAGE_DIRTY 2
+
+struct ps3vram_tag {
+ unsigned int address;
+ unsigned int flags;
+};
+
+struct ps3vram_cache {
+ unsigned int page_count;
+ unsigned int page_size;
+ struct ps3vram_tag *tags;
+};
+
+struct ps3vram_priv {
+ u64 memory_handle;
+ u64 context_handle;
+ u32 *ctrl;
+ u32 *reports;
+ u8 __iomem *ddr_base;
+ u8 *xdr_buf;
+
+ u32 *fifo_base;
+ u32 *fifo_ptr;
+
+ struct device *dev;
+ struct ps3vram_cache cache;
+
+ /* Used to serialize cache/DMA operations */
+ struct mutex lock;
+};
+
+#define DMA_NOTIFIER_HANDLE_BASE 0x66604200 /* first DMA notifier handle */
+#define DMA_NOTIFIER_OFFSET_BASE 0x1000 /* first DMA notifier offset */
+#define DMA_NOTIFIER_SIZE 0x40
+#define NOTIFIER 7 /* notifier used for completion report */
+
+/* A trailing '-' means to subtract off ps3fb_videomemory.size */
+char *size = "256M-";
+module_param(size, charp, 0);
+MODULE_PARM_DESC(size, "memory size");
+
+static u32 *ps3vram_get_notifier(u32 *reports, int notifier)
+{
+ return (void *) reports +
+ DMA_NOTIFIER_OFFSET_BASE +
+ DMA_NOTIFIER_SIZE * notifier;
+}
+
+static void ps3vram_notifier_reset(struct mtd_info *mtd)
+{
+ int i;
+
+ struct ps3vram_priv *priv = mtd->priv;
+ u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
+ for (i = 0; i < 4; i++)
+ notify[i] = 0xffffffff;
+}
+
+static int ps3vram_notifier_wait(struct mtd_info *mtd, unsigned int timeout_ms)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+ u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
+ unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
+
+ do {
+ if (!notify[3])
+ return 0;
+ msleep(1);
+ } while (time_before(jiffies, timeout));
+
+ return -ETIMEDOUT;
+}
+
+static void ps3vram_init_ring(struct mtd_info *mtd)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+
+ priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
+ priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET;
+}
+
+static int ps3vram_wait_ring(struct mtd_info *mtd, unsigned int timeout_ms)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+ unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
+
+ do {
+ if (priv->ctrl[CTRL_PUT] == priv->ctrl[CTRL_GET])
+ return 0;
+ msleep(1);
+ } while (time_before(jiffies, timeout));
+
+ dev_dbg(priv->dev, "%s:%d: FIFO timeout (%08x/%08x/%08x)\n", __func__,
+ __LINE__, priv->ctrl[CTRL_PUT], priv->ctrl[CTRL_GET],
+ priv->ctrl[CTRL_TOP]);
+
+ return -ETIMEDOUT;
+}
+
+static void ps3vram_out_ring(struct ps3vram_priv *priv, u32 data)
+{
+ *(priv->fifo_ptr)++ = data;
+}
+
+static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan,
+ u32 tag, u32 size)
+{
+ ps3vram_out_ring(priv, (size << 18) | (chan << 13) | tag);
+}
+
+static void ps3vram_rewind_ring(struct mtd_info *mtd)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+ u64 status;
+
+ ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET));
+
+ priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
+
+ /* asking the HV for a blit will kick the fifo */
+ status = lv1_gpu_context_attribute(priv->context_handle,
+ L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
+ 0, 0, 0, 0);
+ if (status)
+ dev_err(priv->dev, "%s:%d: lv1_gpu_context_attribute failed\n",
+ __func__, __LINE__);
+
+ priv->fifo_ptr = priv->fifo_base;
+}
+
+static void ps3vram_fire_ring(struct mtd_info *mtd)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+ u64 status;
+
+ mutex_lock(&ps3_gpu_mutex);
+
+ priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET +
+ (priv->fifo_ptr - priv->fifo_base) * sizeof(u32);
+
+ /* asking the HV for a blit will kick the fifo */
+ status = lv1_gpu_context_attribute(priv->context_handle,
+ L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
+ 0, 0, 0, 0);
+ if (status)
+ dev_err(priv->dev, "%s:%d: lv1_gpu_context_attribute failed\n",
+ __func__, __LINE__);
+
+ if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) >
+ FIFO_SIZE - 1024) {
+ dev_dbg(priv->dev, "%s:%d: fifo full, rewinding\n", __func__,
+ __LINE__);
+ ps3vram_wait_ring(mtd, 200);
+ ps3vram_rewind_ring(mtd);
+ }
+
+ mutex_unlock(&ps3_gpu_mutex);
+}
+
+static void ps3vram_bind(struct mtd_info *mtd)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+
+ ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1);
+ ps3vram_out_ring(priv, 0x31337303);
+ ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x180, 3);
+ ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER);
+ ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */
+ ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */
+
+ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0, 1);
+ ps3vram_out_ring(priv, 0x3137c0de);
+ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x180, 3);
+ ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER);
+ ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */
+ ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */
+
+ ps3vram_fire_ring(mtd);
+}
+
+static int ps3vram_upload(struct mtd_info *mtd, unsigned int src_offset,
+ unsigned int dst_offset, int len, int count)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+
+ ps3vram_begin_ring(priv, UPLOAD_SUBCH,
+ NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
+ ps3vram_out_ring(priv, XDR_IOIF + src_offset);
+ ps3vram_out_ring(priv, dst_offset);
+ ps3vram_out_ring(priv, len);
+ ps3vram_out_ring(priv, len);
+ ps3vram_out_ring(priv, len);
+ ps3vram_out_ring(priv, count);
+ ps3vram_out_ring(priv, (1 << 8) | 1);
+ ps3vram_out_ring(priv, 0);
+
+ ps3vram_notifier_reset(mtd);
+ ps3vram_begin_ring(priv, UPLOAD_SUBCH,
+ NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
+ ps3vram_out_ring(priv, 0);
+ ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x100, 1);
+ ps3vram_out_ring(priv, 0);
+ ps3vram_fire_ring(mtd);
+ if (ps3vram_notifier_wait(mtd, 200) < 0) {
+ dev_dbg(priv->dev, "%s:%d: notifier timeout\n", __func__,
+ __LINE__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ps3vram_download(struct mtd_info *mtd, unsigned int src_offset,
+ unsigned int dst_offset, int len, int count)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+
+ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
+ NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
+ ps3vram_out_ring(priv, src_offset);
+ ps3vram_out_ring(priv, XDR_IOIF + dst_offset);
+ ps3vram_out_ring(priv, len);
+ ps3vram_out_ring(priv, len);
+ ps3vram_out_ring(priv, len);
+ ps3vram_out_ring(priv, count);
+ ps3vram_out_ring(priv, (1 << 8) | 1);
+ ps3vram_out_ring(priv, 0);
+
+ ps3vram_notifier_reset(mtd);
+ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
+ NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
+ ps3vram_out_ring(priv, 0);
+ ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x100, 1);
+ ps3vram_out_ring(priv, 0);
+ ps3vram_fire_ring(mtd);
+ if (ps3vram_notifier_wait(mtd, 200) < 0) {
+ dev_dbg(priv->dev, "%s:%d: notifier timeout\n", __func__,
+ __LINE__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void ps3vram_cache_evict(struct mtd_info *mtd, int entry)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+ struct ps3vram_cache *cache = &priv->cache;
+
+ if (cache->tags[entry].flags & CACHE_PAGE_DIRTY) {
+ dev_dbg(priv->dev, "%s:%d: flushing %d : 0x%08x\n", __func__,
+ __LINE__, entry, cache->tags[entry].address);
+ if (ps3vram_upload(mtd,
+ CACHE_OFFSET + entry * cache->page_size,
+ cache->tags[entry].address,
+ DMA_PAGE_SIZE,
+ cache->page_size / DMA_PAGE_SIZE) < 0) {
+ dev_dbg(priv->dev, "%s:%d: failed to upload from "
+ "0x%x to 0x%x size 0x%x\n", __func__, __LINE__,
+ entry * cache->page_size,
+ cache->tags[entry].address, cache->page_size);
+ }
+ cache->tags[entry].flags &= ~CACHE_PAGE_DIRTY;
+ }
+}
+
+static void ps3vram_cache_load(struct mtd_info *mtd, int entry,
+ unsigned int address)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+ struct ps3vram_cache *cache = &priv->cache;
+
+ dev_dbg(priv->dev, "%s:%d: fetching %d : 0x%08x\n", __func__, __LINE__,
+ entry, address);
+ if (ps3vram_download(mtd,
+ address,
+ CACHE_OFFSET + entry * cache->page_size,
+ DMA_PAGE_SIZE,
+ cache->page_size / DMA_PAGE_SIZE) < 0) {
+ dev_err(priv->dev, "%s:%d: failed to download from "
+ "0x%x to 0x%x size 0x%x\n", __func__, __LINE__, address,
+ entry * cache->page_size, cache->page_size);
+ }
+
+ cache->tags[entry].address = address;
+ cache->tags[entry].flags |= CACHE_PAGE_PRESENT;
+}
+
+
+static void ps3vram_cache_flush(struct mtd_info *mtd)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+ struct ps3vram_cache *cache = &priv->cache;
+ int i;
+
+ dev_dbg(priv->dev, "%s:%d: FLUSH\n", __func__, __LINE__);
+ for (i = 0; i < cache->page_count; i++) {
+ ps3vram_cache_evict(mtd, i);
+ cache->tags[i].flags = 0;
+ }
+}
+
+static unsigned int ps3vram_cache_match(struct mtd_info *mtd, loff_t address)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+ struct ps3vram_cache *cache = &priv->cache;
+ unsigned int base;
+ unsigned int offset;
+ int i;
+ static int counter;
+
+ offset = (unsigned int) (address & (cache->page_size - 1));
+ base = (unsigned int) (address - offset);
+
+ /* fully associative check */
+ for (i = 0; i < cache->page_count; i++) {
+ if ((cache->tags[i].flags & CACHE_PAGE_PRESENT) &&
+ cache->tags[i].address == base) {
+ dev_dbg(priv->dev, "%s:%d: found entry %d : 0x%08x\n",
+ __func__, __LINE__, i, cache->tags[i].address);
+ return i;
+ }
+ }
+
+ /* choose a random entry */
+ i = (jiffies + (counter++)) % cache->page_count;
+ dev_dbg(priv->dev, "%s:%d: using entry %d\n", __func__, __LINE__, i);
+
+ ps3vram_cache_evict(mtd, i);
+ ps3vram_cache_load(mtd, i, base);
+
+ return i;
+}
+
+static int ps3vram_cache_init(struct mtd_info *mtd)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+
+ priv->cache.page_count = CACHE_PAGE_COUNT;
+ priv->cache.page_size = CACHE_PAGE_SIZE;
+ priv->cache.tags = kzalloc(sizeof(struct ps3vram_tag) *
+ CACHE_PAGE_COUNT, GFP_KERNEL);
+ if (priv->cache.tags == NULL) {
+ dev_err(priv->dev, "%s:%d: could not allocate cache tags\n",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ dev_info(priv->dev, "created ram cache: %d entries, %d KiB each\n",
+ CACHE_PAGE_COUNT, CACHE_PAGE_SIZE / 1024);
+
+ return 0;
+}
+
+static void ps3vram_cache_cleanup(struct mtd_info *mtd)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+
+ ps3vram_cache_flush(mtd);
+ kfree(priv->cache.tags);
+}
+
+static int ps3vram_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+
+ if (instr->addr + instr->len > mtd->size)
+ return -EINVAL;
+
+ mutex_lock(&priv->lock);
+
+ ps3vram_cache_flush(mtd);
+
+ /* Set bytes to 0xFF */
+ memset_io(priv->ddr_base + instr->addr, 0xFF, instr->len);
+
+ mutex_unlock(&priv->lock);
+
+ instr->state = MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+
+ return 0;
+}
+
+static int ps3vram_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+ unsigned int cached, count;
+
+ dev_dbg(priv->dev, "%s:%d: from=0x%08x len=0x%zx\n", __func__, __LINE__,
+ (unsigned int)from, len);
+
+ if (from >= mtd->size)
+ return -EINVAL;
+
+ if (len > mtd->size - from)
+ len = mtd->size - from;
+
+ /* Copy from vram to buf */
+ count = len;
+ while (count) {
+ unsigned int offset, avail;
+ unsigned int entry;
+
+ offset = (unsigned int) (from & (priv->cache.page_size - 1));
+ avail = priv->cache.page_size - offset;
+
+ mutex_lock(&priv->lock);
+
+ entry = ps3vram_cache_match(mtd, from);
+ cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
+
+ dev_dbg(priv->dev, "%s:%d: from=%08x cached=%08x offset=%08x "
+ "avail=%08x count=%08x\n", __func__, __LINE__,
+ (unsigned int)from, cached, offset, avail, count);
+
+ if (avail > count)
+ avail = count;
+ memcpy(buf, priv->xdr_buf + cached, avail);
+
+ mutex_unlock(&priv->lock);
+
+ buf += avail;
+ count -= avail;
+ from += avail;
+ }
+
+ *retlen = len;
+ return 0;
+}
+
+static int ps3vram_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct ps3vram_priv *priv = mtd->priv;
+ unsigned int cached, count;
+
+ if (to >= mtd->size)
+ return -EINVAL;
+
+ if (len > mtd->size - to)
+ len = mtd->size - to;
+
+ /* Copy from buf to vram */
+ count = len;
+ while (count) {
+ unsigned int offset, avail;
+ unsigned int entry;
+
+ offset = (unsigned int) (to & (priv->cache.page_size - 1));
+ avail = priv->cache.page_size - offset;
+
+ mutex_lock(&priv->lock);
+
+ entry = ps3vram_cache_match(mtd, to);
+ cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
+
+ dev_dbg(priv->dev, "%s:%d: to=%08x cached=%08x offset=%08x "
+ "avail=%08x count=%08x\n", __func__, __LINE__,
+ (unsigned int)to, cached, offset, avail, count);
+
+ if (avail > count)
+ avail = count;
+ memcpy(priv->xdr_buf + cached, buf, avail);
+
+ priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY;
+
+ mutex_unlock(&priv->lock);
+
+ buf += avail;
+ count -= avail;
+ to += avail;
+ }
+
+ *retlen = len;
+ return 0;
+}
+
+static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
+{
+ struct ps3vram_priv *priv;
+ int status;
+ u64 ddr_lpar;
+ u64 ctrl_lpar;
+ u64 info_lpar;
+ u64 reports_lpar;
+ u64 ddr_size;
+ u64 reports_size;
+ int ret = -ENOMEM;
+ char *rest;
+
+ ret = -EIO;
+ ps3vram_mtd.priv = kzalloc(sizeof(struct ps3vram_priv), GFP_KERNEL);
+ if (!ps3vram_mtd.priv)
+ goto out;
+ priv = ps3vram_mtd.priv;
+
+ mutex_init(&priv->lock);
+ priv->dev = &dev->core;
+
+ /* Allocate XDR buffer (1MiB aligned) */
+ priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL,
+ get_order(XDR_BUF_SIZE));
+ if (priv->xdr_buf == NULL) {
+ dev_dbg(&dev->core, "%s:%d: could not allocate XDR buffer\n",
+ __func__, __LINE__);
+ ret = -ENOMEM;
+ goto out_free_priv;
+ }
+
+ /* Put FIFO at begginning of XDR buffer */
+ priv->fifo_base = (u32 *) (priv->xdr_buf + FIFO_OFFSET);
+ priv->fifo_ptr = priv->fifo_base;
+
+ /* XXX: Need to open GPU, in case ps3fb or snd_ps3 aren't loaded */
+ if (ps3_open_hv_device(dev)) {
+ dev_err(&dev->core, "%s:%d: ps3_open_hv_device failed\n",
+ __func__, __LINE__);
+ ret = -EAGAIN;
+ goto out_close_gpu;
+ }
+
+ /* Request memory */
+ status = -1;
+ ddr_size = memparse(size, &rest);
+ if (*rest == '-')
+ ddr_size -= ps3fb_videomemory.size;
+ ddr_size = ALIGN(ddr_size, 1024*1024);
+ if (ddr_size <= 0) {
+ dev_err(&dev->core, "%s:%d: specified size is too small\n",
+ __func__, __LINE__);
+ ret = -EINVAL;
+ goto out_close_gpu;
+ }
+
+ while (ddr_size > 0) {
+ status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0,
+ &priv->memory_handle,
+ &ddr_lpar);
+ if (!status)
+ break;
+ ddr_size -= 1024*1024;
+ }
+ if (status || ddr_size <= 0) {
+ dev_err(&dev->core, "%s:%d: lv1_gpu_memory_allocate failed\n",
+ __func__, __LINE__);
+ ret = -ENOMEM;
+ goto out_free_xdr_buf;
+ }
+
+ /* Request context */
+ status = lv1_gpu_context_allocate(priv->memory_handle,
+ 0,
+ &priv->context_handle,
+ &ctrl_lpar,
+ &info_lpar,
+ &reports_lpar,
+ &reports_size);
+ if (status) {
+ dev_err(&dev->core, "%s:%d: lv1_gpu_context_allocate failed\n",
+ __func__, __LINE__);
+ ret = -ENOMEM;
+ goto out_free_memory;
+ }
+
+ /* Map XDR buffer to RSX */
+ status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
+ ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)),
+ XDR_BUF_SIZE, 0);
+ if (status) {
+ dev_err(&dev->core, "%s:%d: lv1_gpu_context_iomap failed\n",
+ __func__, __LINE__);
+ ret = -ENOMEM;
+ goto out_free_context;
+ }
+
+ priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE);
+
+ if (!priv->ddr_base) {
+ dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__,
+ __LINE__);
+ ret = -ENOMEM;
+ goto out_free_context;
+ }
+
+ priv->ctrl = ioremap(ctrl_lpar, 64 * 1024);
+ if (!priv->ctrl) {
+ dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__,
+ __LINE__);
+ ret = -ENOMEM;
+ goto out_unmap_vram;
+ }
+
+ priv->reports = ioremap(reports_lpar, reports_size);
+ if (!priv->reports) {
+ dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__,
+ __LINE__);
+ ret = -ENOMEM;
+ goto out_unmap_ctrl;
+ }
+
+ mutex_lock(&ps3_gpu_mutex);
+ ps3vram_init_ring(&ps3vram_mtd);
+ mutex_unlock(&ps3_gpu_mutex);
+
+ ps3vram_mtd.name = "ps3vram";
+ ps3vram_mtd.size = ddr_size;
+ ps3vram_mtd.flags = MTD_CAP_RAM;
+ ps3vram_mtd.erase = ps3vram_erase;
+ ps3vram_mtd.point = NULL;
+ ps3vram_mtd.unpoint = NULL;
+ ps3vram_mtd.read = ps3vram_read;
+ ps3vram_mtd.write = ps3vram_write;
+ ps3vram_mtd.owner = THIS_MODULE;
+ ps3vram_mtd.type = MTD_RAM;
+ ps3vram_mtd.erasesize = CACHE_PAGE_SIZE;
+ ps3vram_mtd.writesize = 1;
+
+ ps3vram_bind(&ps3vram_mtd);
+
+ mutex_lock(&ps3_gpu_mutex);
+ ret = ps3vram_wait_ring(&ps3vram_mtd, 100);
+ mutex_unlock(&ps3_gpu_mutex);
+ if (ret < 0) {
+ dev_err(&dev->core, "%s:%d: failed to initialize channels\n",
+ __func__, __LINE__);
+ ret = -ETIMEDOUT;
+ goto out_unmap_reports;
+ }
+
+ ps3vram_cache_init(&ps3vram_mtd);
+
+ if (add_mtd_device(&ps3vram_mtd)) {
+ dev_err(&dev->core, "%s:%d: add_mtd_device failed\n",
+ __func__, __LINE__);
+ ret = -EAGAIN;
+ goto out_cache_cleanup;
+ }
+
+ dev_info(&dev->core, "reserved %u MiB of gpu memory\n",
+ (unsigned int)(ddr_size / 1024 / 1024));
+
+ return 0;
+
+out_cache_cleanup:
+ ps3vram_cache_cleanup(&ps3vram_mtd);
+out_unmap_reports:
+ iounmap(priv->reports);
+out_unmap_ctrl:
+ iounmap(priv->ctrl);
+out_unmap_vram:
+ iounmap(priv->ddr_base);
+out_free_context:
+ lv1_gpu_context_free(priv->context_handle);
+out_free_memory:
+ lv1_gpu_memory_free(priv->memory_handle);
+out_close_gpu:
+ ps3_close_hv_device(dev);
+out_free_xdr_buf:
+ free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
+out_free_priv:
+ kfree(ps3vram_mtd.priv);
+ ps3vram_mtd.priv = NULL;
+out:
+ return ret;
+}
+
+static int ps3vram_shutdown(struct ps3_system_bus_device *dev)
+{
+ struct ps3vram_priv *priv;
+
+ priv = ps3vram_mtd.priv;
+
+ del_mtd_device(&ps3vram_mtd);
+ ps3vram_cache_cleanup(&ps3vram_mtd);
+ iounmap(priv->reports);
+ iounmap(priv->ctrl);
+ iounmap(priv->ddr_base);
+ lv1_gpu_context_free(priv->context_handle);
+ lv1_gpu_memory_free(priv->memory_handle);
+ ps3_close_hv_device(dev);
+ free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
+ kfree(priv);
+ return 0;
+}
+
+static struct ps3_system_bus_driver ps3vram_driver = {
+ .match_id = PS3_MATCH_ID_GPU,
+ .match_sub_id = PS3_MATCH_SUB_ID_GPU_RAMDISK,
+ .core.name = DEVICE_NAME,
+ .core.owner = THIS_MODULE,
+ .probe = ps3vram_probe,
+ .remove = ps3vram_shutdown,
+ .shutdown = ps3vram_shutdown,
+};
+
+static int __init ps3vram_init(void)
+{
+ return ps3_system_bus_driver_register(&ps3vram_driver);
+}
+
+static void __exit ps3vram_exit(void)
+{
+ ps3_system_bus_driver_unregister(&ps3vram_driver);
+}
+
+module_init(ps3vram_init);
+module_exit(ps3vram_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jim Paris <jim@jtan.com>");
+MODULE_DESCRIPTION("MTD driver for PS3 video RAM");
+MODULE_ALIAS(PS3_MODULE_ALIAS_GPU_RAMDISK);
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 9bf581c4f740..a790c062af1f 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -109,25 +109,25 @@ module_param(shuffle_freq, int, 0);
/* Each memory region corresponds to a minor device */
typedef struct partition_t {
struct mtd_blktrans_dev mbd;
- u_int32_t state;
- u_int32_t *VirtualBlockMap;
- u_int32_t *VirtualPageMap;
- u_int32_t FreeTotal;
+ uint32_t state;
+ uint32_t *VirtualBlockMap;
+ uint32_t *VirtualPageMap;
+ uint32_t FreeTotal;
struct eun_info_t {
- u_int32_t Offset;
- u_int32_t EraseCount;
- u_int32_t Free;
- u_int32_t Deleted;
+ uint32_t Offset;
+ uint32_t EraseCount;
+ uint32_t Free;
+ uint32_t Deleted;
} *EUNInfo;
struct xfer_info_t {
- u_int32_t Offset;
- u_int32_t EraseCount;
- u_int16_t state;
+ uint32_t Offset;
+ uint32_t EraseCount;
+ uint16_t state;
} *XferInfo;
- u_int16_t bam_index;
- u_int32_t *bam_cache;
- u_int16_t DataUnits;
- u_int32_t BlocksPerUnit;
+ uint16_t bam_index;
+ uint32_t *bam_cache;
+ uint16_t DataUnits;
+ uint32_t BlocksPerUnit;
erase_unit_header_t header;
} partition_t;
@@ -199,8 +199,8 @@ static int scan_header(partition_t *part)
static int build_maps(partition_t *part)
{
erase_unit_header_t header;
- u_int16_t xvalid, xtrans, i;
- u_int blocks, j;
+ uint16_t xvalid, xtrans, i;
+ unsigned blocks, j;
int hdr_ok, ret = -1;
ssize_t retval;
loff_t offset;
@@ -269,14 +269,14 @@ static int build_maps(partition_t *part)
/* Set up virtual page map */
blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
- part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
+ part->VirtualBlockMap = vmalloc(blocks * sizeof(uint32_t));
if (!part->VirtualBlockMap)
goto out_XferInfo;
- memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t));
+ memset(part->VirtualBlockMap, 0xff, blocks * sizeof(uint32_t));
part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
- part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t),
+ part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(uint32_t),
GFP_KERNEL);
if (!part->bam_cache)
goto out_VirtualBlockMap;
@@ -290,7 +290,7 @@ static int build_maps(partition_t *part)
offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
ret = part->mbd.mtd->read(part->mbd.mtd, offset,
- part->BlocksPerUnit * sizeof(u_int32_t), &retval,
+ part->BlocksPerUnit * sizeof(uint32_t), &retval,
(unsigned char *)part->bam_cache);
if (ret)
@@ -332,7 +332,7 @@ out:
======================================================================*/
static int erase_xfer(partition_t *part,
- u_int16_t xfernum)
+ uint16_t xfernum)
{
int ret;
struct xfer_info_t *xfer;
@@ -408,7 +408,7 @@ static int prepare_xfer(partition_t *part, int i)
erase_unit_header_t header;
struct xfer_info_t *xfer;
int nbam, ret;
- u_int32_t ctl;
+ uint32_t ctl;
ssize_t retlen;
loff_t offset;
@@ -430,15 +430,15 @@ static int prepare_xfer(partition_t *part, int i)
}
/* Write the BAM stub */
- nbam = (part->BlocksPerUnit * sizeof(u_int32_t) +
+ nbam = (part->BlocksPerUnit * sizeof(uint32_t) +
le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE;
offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
ctl = cpu_to_le32(BLOCK_CONTROL);
- for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
+ for (i = 0; i < nbam; i++, offset += sizeof(uint32_t)) {
- ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint32_t),
&retlen, (u_char *)&ctl);
if (ret)
@@ -461,18 +461,18 @@ static int prepare_xfer(partition_t *part, int i)
======================================================================*/
-static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
- u_int16_t xferunit)
+static int copy_erase_unit(partition_t *part, uint16_t srcunit,
+ uint16_t xferunit)
{
u_char buf[SECTOR_SIZE];
struct eun_info_t *eun;
struct xfer_info_t *xfer;
- u_int32_t src, dest, free, i;
- u_int16_t unit;
+ uint32_t src, dest, free, i;
+ uint16_t unit;
int ret;
ssize_t retlen;
loff_t offset;
- u_int16_t srcunitswap = cpu_to_le16(srcunit);
+ uint16_t srcunitswap = cpu_to_le16(srcunit);
eun = &part->EUNInfo[srcunit];
xfer = &part->XferInfo[xferunit];
@@ -486,7 +486,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
ret = part->mbd.mtd->read(part->mbd.mtd, offset,
- part->BlocksPerUnit * sizeof(u_int32_t),
+ part->BlocksPerUnit * sizeof(uint32_t),
&retlen, (u_char *) (part->bam_cache));
/* mark the cache bad, in case we get an error later */
@@ -503,7 +503,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
offset = xfer->Offset + 20; /* Bad! */
unit = cpu_to_le16(0x7fff);
- ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint16_t),
&retlen, (u_char *) &unit);
if (ret) {
@@ -560,7 +560,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
/* All clear? Then update the LogicalEUN again */
- ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
+ ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(uint16_t),
&retlen, (u_char *)&srcunitswap);
if (ret) {
@@ -605,8 +605,8 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
static int reclaim_block(partition_t *part)
{
- u_int16_t i, eun, xfer;
- u_int32_t best;
+ uint16_t i, eun, xfer;
+ uint32_t best;
int queued, ret;
DEBUG(0, "ftl_cs: reclaiming space...\n");
@@ -723,10 +723,10 @@ static void dump_lists(partition_t *part)
}
#endif
-static u_int32_t find_free(partition_t *part)
+static uint32_t find_free(partition_t *part)
{
- u_int16_t stop, eun;
- u_int32_t blk;
+ uint16_t stop, eun;
+ uint32_t blk;
size_t retlen;
int ret;
@@ -749,7 +749,7 @@ static u_int32_t find_free(partition_t *part)
ret = part->mbd.mtd->read(part->mbd.mtd,
part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
- part->BlocksPerUnit * sizeof(u_int32_t),
+ part->BlocksPerUnit * sizeof(uint32_t),
&retlen, (u_char *) (part->bam_cache));
if (ret) {
@@ -786,7 +786,7 @@ static u_int32_t find_free(partition_t *part)
static int ftl_read(partition_t *part, caddr_t buffer,
u_long sector, u_long nblocks)
{
- u_int32_t log_addr, bsize;
+ uint32_t log_addr, bsize;
u_long i;
int ret;
size_t offset, retlen;
@@ -829,14 +829,14 @@ static int ftl_read(partition_t *part, caddr_t buffer,
======================================================================*/
-static int set_bam_entry(partition_t *part, u_int32_t log_addr,
- u_int32_t virt_addr)
+static int set_bam_entry(partition_t *part, uint32_t log_addr,
+ uint32_t virt_addr)
{
- u_int32_t bsize, blk, le_virt_addr;
+ uint32_t bsize, blk, le_virt_addr;
#ifdef PSYCHO_DEBUG
- u_int32_t old_addr;
+ uint32_t old_addr;
#endif
- u_int16_t eun;
+ uint16_t eun;
int ret;
size_t retlen, offset;
@@ -845,11 +845,11 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr,
bsize = 1 << part->header.EraseUnitSize;
eun = log_addr / bsize;
blk = (log_addr % bsize) / SECTOR_SIZE;
- offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
+ offset = (part->EUNInfo[eun].Offset + blk * sizeof(uint32_t) +
le32_to_cpu(part->header.BAMOffset));
#ifdef PSYCHO_DEBUG
- ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(uint32_t),
&retlen, (u_char *)&old_addr);
if (ret) {
printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
@@ -886,7 +886,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr,
#endif
part->bam_cache[blk] = le_virt_addr;
}
- ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint32_t),
&retlen, (u_char *)&le_virt_addr);
if (ret) {
@@ -900,7 +900,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr,
static int ftl_write(partition_t *part, caddr_t buffer,
u_long sector, u_long nblocks)
{
- u_int32_t bsize, log_addr, virt_addr, old_addr, blk;
+ uint32_t bsize, log_addr, virt_addr, old_addr, blk;
u_long i;
int ret;
size_t retlen, offset;
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index 50ce13887f63..73f05227dc8c 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -50,7 +50,7 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
struct INFTLrecord *inftl;
unsigned long temp;
- if (mtd->type != MTD_NANDFLASH)
+ if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX)
return;
/* OK, this is moderately ugly. But probably safe. Alternatives? */
if (memcmp(mtd->name, "DiskOnChip", 10))
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
index 9113628ed1ef..f751dd97c549 100644
--- a/drivers/mtd/inftlmount.c
+++ b/drivers/mtd/inftlmount.c
@@ -63,7 +63,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
* otherwise.
*/
inftl->EraseSize = inftl->mbd.mtd->erasesize;
- inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
+ inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize;
inftl->MediaUnit = BLOCK_NIL;
@@ -187,7 +187,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
mh->BlockMultiplierBits);
inftl->EraseSize = inftl->mbd.mtd->erasesize <<
mh->BlockMultiplierBits;
- inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
+ inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize;
block >>= mh->BlockMultiplierBits;
}
diff --git a/drivers/mtd/lpddr/Kconfig b/drivers/mtd/lpddr/Kconfig
new file mode 100644
index 000000000000..acd4ea9b2278
--- /dev/null
+++ b/drivers/mtd/lpddr/Kconfig
@@ -0,0 +1,22 @@
+# drivers/mtd/chips/Kconfig
+
+menu "LPDDR flash memory drivers"
+ depends on MTD!=n
+
+config MTD_LPDDR
+ tristate "Support for LPDDR flash chips"
+ select MTD_QINFO_PROBE
+ help
+ This option enables support of LPDDR (Low power double data rate)
+ flash chips. Synonymous with Mobile-DDR. It is a new standard for
+ DDR memories, intended for battery-operated systems.
+
+config MTD_QINFO_PROBE
+ tristate "Detect flash chips by QINFO probe"
+ help
+ Device Information for LPDDR chips is offered through the Overlay
+ Window QINFO interface, permits software to be used for entire
+ families of devices. This serves similar purpose of CFI on legacy
+ Flash products
+endmenu
+
diff --git a/drivers/mtd/lpddr/Makefile b/drivers/mtd/lpddr/Makefile
new file mode 100644
index 000000000000..da48e46b5812
--- /dev/null
+++ b/drivers/mtd/lpddr/Makefile
@@ -0,0 +1,6 @@
+#
+# linux/drivers/mtd/lpddr/Makefile
+#
+
+obj-$(CONFIG_MTD_QINFO_PROBE) += qinfo_probe.o
+obj-$(CONFIG_MTD_LPDDR) += lpddr_cmds.o
diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c
new file mode 100644
index 000000000000..e22ca49583e7
--- /dev/null
+++ b/drivers/mtd/lpddr/lpddr_cmds.c
@@ -0,0 +1,796 @@
+/*
+ * LPDDR flash memory device operations. This module provides read, write,
+ * erase, lock/unlock support for LPDDR flash memories
+ * (C) 2008 Korolev Alexey <akorolev@infradead.org>
+ * (C) 2008 Vasiliy Leonenko <vasiliy.leonenko@gmail.com>
+ * Many thanks to Roman Borisov for intial enabling
+ *
+ * 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.
+ * TODO:
+ * Implement VPP management
+ * Implement XIP support
+ * Implement OTP support
+ */
+#include <linux/mtd/pfow.h>
+#include <linux/mtd/qinfo.h>
+
+static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len,
+ size_t *retlen, u_char *buf);
+static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to,
+ size_t len, size_t *retlen, const u_char *buf);
+static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs,
+ unsigned long count, loff_t to, size_t *retlen);
+static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr);
+static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
+static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
+ size_t *retlen, void **mtdbuf, resource_size_t *phys);
+static void lpddr_unpoint(struct mtd_info *mtd, loff_t adr, size_t len);
+static int get_chip(struct map_info *map, struct flchip *chip, int mode);
+static int chip_ready(struct map_info *map, struct flchip *chip, int mode);
+static void put_chip(struct map_info *map, struct flchip *chip);
+
+struct mtd_info *lpddr_cmdset(struct map_info *map)
+{
+ struct lpddr_private *lpddr = map->fldrv_priv;
+ struct flchip_shared *shared;
+ struct flchip *chip;
+ struct mtd_info *mtd;
+ int numchips;
+ int i, j;
+
+ mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
+ if (!mtd) {
+ printk(KERN_ERR "Failed to allocate memory for MTD device\n");
+ return NULL;
+ }
+ mtd->priv = map;
+ mtd->type = MTD_NORFLASH;
+
+ /* Fill in the default mtd operations */
+ mtd->read = lpddr_read;
+ mtd->type = MTD_NORFLASH;
+ mtd->flags = MTD_CAP_NORFLASH;
+ mtd->flags &= ~MTD_BIT_WRITEABLE;
+ mtd->erase = lpddr_erase;
+ mtd->write = lpddr_write_buffers;
+ mtd->writev = lpddr_writev;
+ mtd->read_oob = NULL;
+ mtd->write_oob = NULL;
+ mtd->sync = NULL;
+ mtd->lock = lpddr_lock;
+ mtd->unlock = lpddr_unlock;
+ mtd->suspend = NULL;
+ mtd->resume = NULL;
+ if (map_is_linear(map)) {
+ mtd->point = lpddr_point;
+ mtd->unpoint = lpddr_unpoint;
+ }
+ mtd->block_isbad = NULL;
+ mtd->block_markbad = NULL;
+ mtd->size = 1 << lpddr->qinfo->DevSizeShift;
+ mtd->erasesize = 1 << lpddr->qinfo->UniformBlockSizeShift;
+ mtd->writesize = 1 << lpddr->qinfo->BufSizeShift;
+
+ shared = kmalloc(sizeof(struct flchip_shared) * lpddr->numchips,
+ GFP_KERNEL);
+ if (!shared) {
+ kfree(lpddr);
+ kfree(mtd);
+ return NULL;
+ }
+
+ chip = &lpddr->chips[0];
+ numchips = lpddr->numchips / lpddr->qinfo->HWPartsNum;
+ for (i = 0; i < numchips; i++) {
+ shared[i].writing = shared[i].erasing = NULL;
+ spin_lock_init(&shared[i].lock);
+ for (j = 0; j < lpddr->qinfo->HWPartsNum; j++) {
+ *chip = lpddr->chips[i];
+ chip->start += j << lpddr->chipshift;
+ chip->oldstate = chip->state = FL_READY;
+ chip->priv = &shared[i];
+ /* those should be reset too since
+ they create memory references. */
+ init_waitqueue_head(&chip->wq);
+ spin_lock_init(&chip->_spinlock);
+ chip->mutex = &chip->_spinlock;
+ chip++;
+ }
+ }
+
+ return mtd;
+}
+EXPORT_SYMBOL(lpddr_cmdset);
+
+static int wait_for_ready(struct map_info *map, struct flchip *chip,
+ unsigned int chip_op_time)
+{
+ unsigned int timeo, reset_timeo, sleep_time;
+ unsigned int dsr;
+ flstate_t chip_state = chip->state;
+ int ret = 0;
+
+ /* set our timeout to 8 times the expected delay */
+ timeo = chip_op_time * 8;
+ if (!timeo)
+ timeo = 500000;
+ reset_timeo = timeo;
+ sleep_time = chip_op_time / 2;
+
+ for (;;) {
+ dsr = CMDVAL(map_read(map, map->pfow_base + PFOW_DSR));
+ if (dsr & DSR_READY_STATUS)
+ break;
+ if (!timeo) {
+ printk(KERN_ERR "%s: Flash timeout error state %d \n",
+ map->name, chip_state);
+ ret = -ETIME;
+ break;
+ }
+
+ /* OK Still waiting. Drop the lock, wait a while and retry. */
+ spin_unlock(chip->mutex);
+ if (sleep_time >= 1000000/HZ) {
+ /*
+ * Half of the normal delay still remaining
+ * can be performed with a sleeping delay instead
+ * of busy waiting.
+ */
+ msleep(sleep_time/1000);
+ timeo -= sleep_time;
+ sleep_time = 1000000/HZ;
+ } else {
+ udelay(1);
+ cond_resched();
+ timeo--;
+ }
+ spin_lock(chip->mutex);
+
+ while (chip->state != chip_state) {
+ /* Someone's suspended the operation: sleep */
+ DECLARE_WAITQUEUE(wait, current);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+ spin_unlock(chip->mutex);
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+ spin_lock(chip->mutex);
+ }
+ if (chip->erase_suspended || chip->write_suspended) {
+ /* Suspend has occured while sleep: reset timeout */
+ timeo = reset_timeo;
+ chip->erase_suspended = chip->write_suspended = 0;
+ }
+ }
+ /* check status for errors */
+ if (dsr & DSR_ERR) {
+ /* Clear DSR*/
+ map_write(map, CMD(~(DSR_ERR)), map->pfow_base + PFOW_DSR);
+ printk(KERN_WARNING"%s: Bad status on wait: 0x%x \n",
+ map->name, dsr);
+ print_drs_error(dsr);
+ ret = -EIO;
+ }
+ chip->state = FL_READY;
+ return ret;
+}
+
+static int get_chip(struct map_info *map, struct flchip *chip, int mode)
+{
+ int ret;
+ DECLARE_WAITQUEUE(wait, current);
+
+ retry:
+ if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)
+ && chip->state != FL_SYNCING) {
+ /*
+ * OK. We have possibility for contension on the write/erase
+ * operations which are global to the real chip and not per
+ * partition. So let's fight it over in the partition which
+ * currently has authority on the operation.
+ *
+ * The rules are as follows:
+ *
+ * - any write operation must own shared->writing.
+ *
+ * - any erase operation must own _both_ shared->writing and
+ * shared->erasing.
+ *
+ * - contension arbitration is handled in the owner's context.
+ *
+ * The 'shared' struct can be read and/or written only when
+ * its lock is taken.
+ */
+ struct flchip_shared *shared = chip->priv;
+ struct flchip *contender;
+ spin_lock(&shared->lock);
+ contender = shared->writing;
+ if (contender && contender != chip) {
+ /*
+ * The engine to perform desired operation on this
+ * partition is already in use by someone else.
+ * Let's fight over it in the context of the chip
+ * currently using it. If it is possible to suspend,
+ * that other partition will do just that, otherwise
+ * it'll happily send us to sleep. In any case, when
+ * get_chip returns success we're clear to go ahead.
+ */
+ ret = spin_trylock(contender->mutex);
+ spin_unlock(&shared->lock);
+ if (!ret)
+ goto retry;
+ spin_unlock(chip->mutex);
+ ret = chip_ready(map, contender, mode);
+ spin_lock(chip->mutex);
+
+ if (ret == -EAGAIN) {
+ spin_unlock(contender->mutex);
+ goto retry;
+ }
+ if (ret) {
+ spin_unlock(contender->mutex);
+ return ret;
+ }
+ spin_lock(&shared->lock);
+
+ /* We should not own chip if it is already in FL_SYNCING
+ * state. Put contender and retry. */
+ if (chip->state == FL_SYNCING) {
+ put_chip(map, contender);
+ spin_unlock(contender->mutex);
+ goto retry;
+ }
+ spin_unlock(contender->mutex);
+ }
+
+ /* Check if we have suspended erase on this chip.
+ Must sleep in such a case. */
+ if (mode == FL_ERASING && shared->erasing
+ && shared->erasing->oldstate == FL_ERASING) {
+ spin_unlock(&shared->lock);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+ spin_unlock(chip->mutex);
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+ spin_lock(chip->mutex);
+ goto retry;
+ }
+
+ /* We now own it */
+ shared->writing = chip;
+ if (mode == FL_ERASING)
+ shared->erasing = chip;
+ spin_unlock(&shared->lock);
+ }
+
+ ret = chip_ready(map, chip, mode);
+ if (ret == -EAGAIN)
+ goto retry;
+
+ return ret;
+}
+
+static int chip_ready(struct map_info *map, struct flchip *chip, int mode)
+{
+ struct lpddr_private *lpddr = map->fldrv_priv;
+ int ret = 0;
+ DECLARE_WAITQUEUE(wait, current);
+
+ /* Prevent setting state FL_SYNCING for chip in suspended state. */
+ if (FL_SYNCING == mode && FL_READY != chip->oldstate)
+ goto sleep;
+
+ switch (chip->state) {
+ case FL_READY:
+ case FL_JEDEC_QUERY:
+ return 0;
+
+ case FL_ERASING:
+ if (!lpddr->qinfo->SuspEraseSupp ||
+ !(mode == FL_READY || mode == FL_POINT))
+ goto sleep;
+
+ map_write(map, CMD(LPDDR_SUSPEND),
+ map->pfow_base + PFOW_PROGRAM_ERASE_SUSPEND);
+ chip->oldstate = FL_ERASING;
+ chip->state = FL_ERASE_SUSPENDING;
+ ret = wait_for_ready(map, chip, 0);
+ if (ret) {
+ /* Oops. something got wrong. */
+ /* Resume and pretend we weren't here. */
+ map_write(map, CMD(LPDDR_RESUME),
+ map->pfow_base + PFOW_COMMAND_CODE);
+ map_write(map, CMD(LPDDR_START_EXECUTION),
+ map->pfow_base + PFOW_COMMAND_EXECUTE);
+ chip->state = FL_ERASING;
+ chip->oldstate = FL_READY;
+ printk(KERN_ERR "%s: suspend operation failed."
+ "State may be wrong \n", map->name);
+ return -EIO;
+ }
+ chip->erase_suspended = 1;
+ chip->state = FL_READY;
+ return 0;
+ /* Erase suspend */
+ case FL_POINT:
+ /* Only if there's no operation suspended... */
+ if (mode == FL_READY && chip->oldstate == FL_READY)
+ return 0;
+
+ default:
+sleep:
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+ spin_unlock(chip->mutex);
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+ spin_lock(chip->mutex);
+ return -EAGAIN;
+ }
+}
+
+static void put_chip(struct map_info *map, struct flchip *chip)
+{
+ if (chip->priv) {
+ struct flchip_shared *shared = chip->priv;
+ spin_lock(&shared->lock);
+ if (shared->writing == chip && chip->oldstate == FL_READY) {
+ /* We own the ability to write, but we're done */
+ shared->writing = shared->erasing;
+ if (shared->writing && shared->writing != chip) {
+ /* give back the ownership */
+ struct flchip *loaner = shared->writing;
+ spin_lock(loaner->mutex);
+ spin_unlock(&shared->lock);
+ spin_unlock(chip->mutex);
+ put_chip(map, loaner);
+ spin_lock(chip->mutex);
+ spin_unlock(loaner->mutex);
+ wake_up(&chip->wq);
+ return;
+ }
+ shared->erasing = NULL;
+ shared->writing = NULL;
+ } else if (shared->erasing == chip && shared->writing != chip) {
+ /*
+ * We own the ability to erase without the ability
+ * to write, which means the erase was suspended
+ * and some other partition is currently writing.
+ * Don't let the switch below mess things up since
+ * we don't have ownership to resume anything.
+ */
+ spin_unlock(&shared->lock);
+ wake_up(&chip->wq);
+ return;
+ }
+ spin_unlock(&shared->lock);
+ }
+
+ switch (chip->oldstate) {
+ case FL_ERASING:
+ chip->state = chip->oldstate;
+ map_write(map, CMD(LPDDR_RESUME),
+ map->pfow_base + PFOW_COMMAND_CODE);
+ map_write(map, CMD(LPDDR_START_EXECUTION),
+ map->pfow_base + PFOW_COMMAND_EXECUTE);
+ chip->oldstate = FL_READY;
+ chip->state = FL_ERASING;
+ break;
+ case FL_READY:
+ break;
+ default:
+ printk(KERN_ERR "%s: put_chip() called with oldstate %d!\n",
+ map->name, chip->oldstate);
+ }
+ wake_up(&chip->wq);
+}
+
+int do_write_buffer(struct map_info *map, struct flchip *chip,
+ unsigned long adr, const struct kvec **pvec,
+ unsigned long *pvec_seek, int len)
+{
+ struct lpddr_private *lpddr = map->fldrv_priv;
+ map_word datum;
+ int ret, wbufsize, word_gap, words;
+ const struct kvec *vec;
+ unsigned long vec_seek;
+ unsigned long prog_buf_ofs;
+
+ wbufsize = 1 << lpddr->qinfo->BufSizeShift;
+
+ spin_lock(chip->mutex);
+ ret = get_chip(map, chip, FL_WRITING);
+ if (ret) {
+ spin_unlock(chip->mutex);
+ return ret;
+ }
+ /* Figure out the number of words to write */
+ word_gap = (-adr & (map_bankwidth(map)-1));
+ words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map);
+ if (!word_gap) {
+ words--;
+ } else {
+ word_gap = map_bankwidth(map) - word_gap;
+ adr -= word_gap;
+ datum = map_word_ff(map);
+ }
+ /* Write data */
+ /* Get the program buffer offset from PFOW register data first*/
+ prog_buf_ofs = map->pfow_base + CMDVAL(map_read(map,
+ map->pfow_base + PFOW_PROGRAM_BUFFER_OFFSET));
+ vec = *pvec;
+ vec_seek = *pvec_seek;
+ do {
+ int n = map_bankwidth(map) - word_gap;
+
+ if (n > vec->iov_len - vec_seek)
+ n = vec->iov_len - vec_seek;
+ if (n > len)
+ n = len;
+
+ if (!word_gap && (len < map_bankwidth(map)))
+ datum = map_word_ff(map);
+
+ datum = map_word_load_partial(map, datum,
+ vec->iov_base + vec_seek, word_gap, n);
+
+ len -= n;
+ word_gap += n;
+ if (!len || word_gap == map_bankwidth(map)) {
+ map_write(map, datum, prog_buf_ofs);
+ prog_buf_ofs += map_bankwidth(map);
+ word_gap = 0;
+ }
+
+ vec_seek += n;
+ if (vec_seek == vec->iov_len) {
+ vec++;
+ vec_seek = 0;
+ }
+ } while (len);
+ *pvec = vec;
+ *pvec_seek = vec_seek;
+
+ /* GO GO GO */
+ send_pfow_command(map, LPDDR_BUFF_PROGRAM, adr, wbufsize, NULL);
+ chip->state = FL_WRITING;
+ ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->ProgBufferTime));
+ if (ret) {
+ printk(KERN_WARNING"%s Buffer program error: %d at %lx; \n",
+ map->name, ret, adr);
+ goto out;
+ }
+
+ out: put_chip(map, chip);
+ spin_unlock(chip->mutex);
+ return ret;
+}
+
+int do_erase_oneblock(struct mtd_info *mtd, loff_t adr)
+{
+ struct map_info *map = mtd->priv;
+ struct lpddr_private *lpddr = map->fldrv_priv;
+ int chipnum = adr >> lpddr->chipshift;
+ struct flchip *chip = &lpddr->chips[chipnum];
+ int ret;
+
+ spin_lock(chip->mutex);
+ ret = get_chip(map, chip, FL_ERASING);
+ if (ret) {
+ spin_unlock(chip->mutex);
+ return ret;
+ }
+ send_pfow_command(map, LPDDR_BLOCK_ERASE, adr, 0, NULL);
+ chip->state = FL_ERASING;
+ ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->BlockEraseTime)*1000);
+ if (ret) {
+ printk(KERN_WARNING"%s Erase block error %d at : %llx\n",
+ map->name, ret, adr);
+ goto out;
+ }
+ out: put_chip(map, chip);
+ spin_unlock(chip->mutex);
+ return ret;
+}
+
+static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct map_info *map = mtd->priv;
+ struct lpddr_private *lpddr = map->fldrv_priv;
+ int chipnum = adr >> lpddr->chipshift;
+ struct flchip *chip = &lpddr->chips[chipnum];
+ int ret = 0;
+
+ spin_lock(chip->mutex);
+ ret = get_chip(map, chip, FL_READY);
+ if (ret) {
+ spin_unlock(chip->mutex);
+ return ret;
+ }
+
+ map_copy_from(map, buf, adr, len);
+ *retlen = len;
+
+ put_chip(map, chip);
+ spin_unlock(chip->mutex);
+ return ret;
+}
+
+static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
+ size_t *retlen, void **mtdbuf, resource_size_t *phys)
+{
+ struct map_info *map = mtd->priv;
+ struct lpddr_private *lpddr = map->fldrv_priv;
+ int chipnum = adr >> lpddr->chipshift;
+ unsigned long ofs, last_end = 0;
+ struct flchip *chip = &lpddr->chips[chipnum];
+ int ret = 0;
+
+ if (!map->virt || (adr + len > mtd->size))
+ return -EINVAL;
+
+ /* ofs: offset within the first chip that the first read should start */
+ ofs = adr - (chipnum << lpddr->chipshift);
+
+ *mtdbuf = (void *)map->virt + chip->start + ofs;
+ *retlen = 0;
+
+ while (len) {
+ unsigned long thislen;
+
+ if (chipnum >= lpddr->numchips)
+ break;
+
+ /* We cannot point across chips that are virtually disjoint */
+ if (!last_end)
+ last_end = chip->start;
+ else if (chip->start != last_end)
+ break;
+
+ if ((len + ofs - 1) >> lpddr->chipshift)
+ thislen = (1<<lpddr->chipshift) - ofs;
+ else
+ thislen = len;
+ /* get the chip */
+ spin_lock(chip->mutex);
+ ret = get_chip(map, chip, FL_POINT);
+ spin_unlock(chip->mutex);
+ if (ret)
+ break;
+
+ chip->state = FL_POINT;
+ chip->ref_point_counter++;
+ *retlen += thislen;
+ len -= thislen;
+
+ ofs = 0;
+ last_end += 1 << lpddr->chipshift;
+ chipnum++;
+ chip = &lpddr->chips[chipnum];
+ }
+ return 0;
+}
+
+static void lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len)
+{
+ struct map_info *map = mtd->priv;
+ struct lpddr_private *lpddr = map->fldrv_priv;
+ int chipnum = adr >> lpddr->chipshift;
+ unsigned long ofs;
+
+ /* ofs: offset within the first chip that the first read should start */
+ ofs = adr - (chipnum << lpddr->chipshift);
+
+ while (len) {
+ unsigned long thislen;
+ struct flchip *chip;
+
+ chip = &lpddr->chips[chipnum];
+ if (chipnum >= lpddr->numchips)
+ break;
+
+ if ((len + ofs - 1) >> lpddr->chipshift)
+ thislen = (1<<lpddr->chipshift) - ofs;
+ else
+ thislen = len;
+
+ spin_lock(chip->mutex);
+ if (chip->state == FL_POINT) {
+ chip->ref_point_counter--;
+ if (chip->ref_point_counter == 0)
+ chip->state = FL_READY;
+ } else
+ printk(KERN_WARNING "%s: Warning: unpoint called on non"
+ "pointed region\n", map->name);
+
+ put_chip(map, chip);
+ spin_unlock(chip->mutex);
+
+ len -= thislen;
+ ofs = 0;
+ chipnum++;
+ }
+}
+
+static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct kvec vec;
+
+ vec.iov_base = (void *) buf;
+ vec.iov_len = len;
+
+ return lpddr_writev(mtd, &vec, 1, to, retlen);
+}
+
+
+static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs,
+ unsigned long count, loff_t to, size_t *retlen)
+{
+ struct map_info *map = mtd->priv;
+ struct lpddr_private *lpddr = map->fldrv_priv;
+ int ret = 0;
+ int chipnum;
+ unsigned long ofs, vec_seek, i;
+ int wbufsize = 1 << lpddr->qinfo->BufSizeShift;
+
+ size_t len = 0;
+
+ for (i = 0; i < count; i++)
+ len += vecs[i].iov_len;
+
+ *retlen = 0;
+ if (!len)
+ return 0;
+
+ chipnum = to >> lpddr->chipshift;
+
+ ofs = to;
+ vec_seek = 0;
+
+ do {
+ /* We must not cross write block boundaries */
+ int size = wbufsize - (ofs & (wbufsize-1));
+
+ if (size > len)
+ size = len;
+
+ ret = do_write_buffer(map, &lpddr->chips[chipnum],
+ ofs, &vecs, &vec_seek, size);
+ if (ret)
+ return ret;
+
+ ofs += size;
+ (*retlen) += size;
+ len -= size;
+
+ /* Be nice and reschedule with the chip in a usable
+ * state for other processes */
+ cond_resched();
+
+ } while (len);
+
+ return 0;
+}
+
+static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ unsigned long ofs, len;
+ int ret;
+ struct map_info *map = mtd->priv;
+ struct lpddr_private *lpddr = map->fldrv_priv;
+ int size = 1 << lpddr->qinfo->UniformBlockSizeShift;
+
+ ofs = instr->addr;
+ len = instr->len;
+
+ if (ofs > mtd->size || (len + ofs) > mtd->size)
+ return -EINVAL;
+
+ while (len > 0) {
+ ret = do_erase_oneblock(mtd, ofs);
+ if (ret)
+ return ret;
+ ofs += size;
+ len -= size;
+ }
+ instr->state = MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+
+ return 0;
+}
+
+#define DO_XXLOCK_LOCK 1
+#define DO_XXLOCK_UNLOCK 2
+int do_xxlock(struct mtd_info *mtd, loff_t adr, uint32_t len, int thunk)
+{
+ int ret = 0;
+ struct map_info *map = mtd->priv;
+ struct lpddr_private *lpddr = map->fldrv_priv;
+ int chipnum = adr >> lpddr->chipshift;
+ struct flchip *chip = &lpddr->chips[chipnum];
+
+ spin_lock(chip->mutex);
+ ret = get_chip(map, chip, FL_LOCKING);
+ if (ret) {
+ spin_unlock(chip->mutex);
+ return ret;
+ }
+
+ if (thunk == DO_XXLOCK_LOCK) {
+ send_pfow_command(map, LPDDR_LOCK_BLOCK, adr, adr + len, NULL);
+ chip->state = FL_LOCKING;
+ } else if (thunk == DO_XXLOCK_UNLOCK) {
+ send_pfow_command(map, LPDDR_UNLOCK_BLOCK, adr, adr + len, NULL);
+ chip->state = FL_UNLOCKING;
+ } else
+ BUG();
+
+ ret = wait_for_ready(map, chip, 1);
+ if (ret) {
+ printk(KERN_ERR "%s: block unlock error status %d \n",
+ map->name, ret);
+ goto out;
+ }
+out: put_chip(map, chip);
+ spin_unlock(chip->mutex);
+ return ret;
+}
+
+static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+ return do_xxlock(mtd, ofs, len, DO_XXLOCK_LOCK);
+}
+
+static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
+{
+ return do_xxlock(mtd, ofs, len, DO_XXLOCK_UNLOCK);
+}
+
+int word_program(struct map_info *map, loff_t adr, uint32_t curval)
+{
+ int ret;
+ struct lpddr_private *lpddr = map->fldrv_priv;
+ int chipnum = adr >> lpddr->chipshift;
+ struct flchip *chip = &lpddr->chips[chipnum];
+
+ spin_lock(chip->mutex);
+ ret = get_chip(map, chip, FL_WRITING);
+ if (ret) {
+ spin_unlock(chip->mutex);
+ return ret;
+ }
+
+ send_pfow_command(map, LPDDR_WORD_PROGRAM, adr, 0x00, (map_word *)&curval);
+
+ ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->SingleWordProgTime));
+ if (ret) {
+ printk(KERN_WARNING"%s word_program error at: %llx; val: %x\n",
+ map->name, adr, curval);
+ goto out;
+ }
+
+out: put_chip(map, chip);
+ spin_unlock(chip->mutex);
+ return ret;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexey Korolev <akorolev@infradead.org>");
+MODULE_DESCRIPTION("MTD driver for LPDDR flash chips");
diff --git a/drivers/mtd/lpddr/qinfo_probe.c b/drivers/mtd/lpddr/qinfo_probe.c
new file mode 100644
index 000000000000..79bf40f48b75
--- /dev/null
+++ b/drivers/mtd/lpddr/qinfo_probe.c
@@ -0,0 +1,255 @@
+/*
+ * Probing flash chips with QINFO records.
+ * (C) 2008 Korolev Alexey <akorolev@infradead.org>
+ * (C) 2008 Vasiliy Leonenko <vasiliy.leonenko@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 (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/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <linux/mtd/xip.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/pfow.h>
+#include <linux/mtd/qinfo.h>
+
+static int lpddr_chip_setup(struct map_info *map, struct lpddr_private *lpddr);
+struct mtd_info *lpddr_probe(struct map_info *map);
+static struct lpddr_private *lpddr_probe_chip(struct map_info *map);
+static int lpddr_pfow_present(struct map_info *map,
+ struct lpddr_private *lpddr);
+
+static struct qinfo_query_info qinfo_array[] = {
+ /* General device info */
+ {0, 0, "DevSizeShift", "Device size 2^n bytes"},
+ {0, 3, "BufSizeShift", "Program buffer size 2^n bytes"},
+ /* Erase block information */
+ {1, 1, "TotalBlocksNum", "Total number of blocks"},
+ {1, 2, "UniformBlockSizeShift", "Uniform block size 2^n bytes"},
+ /* Partition information */
+ {2, 1, "HWPartsNum", "Number of hardware partitions"},
+ /* Optional features */
+ {5, 1, "SuspEraseSupp", "Suspend erase supported"},
+ /* Operation typical time */
+ {10, 0, "SingleWordProgTime", "Single word program 2^n u-sec"},
+ {10, 1, "ProgBufferTime", "Program buffer write 2^n u-sec"},
+ {10, 2, "BlockEraseTime", "Block erase 2^n m-sec"},
+ {10, 3, "FullChipEraseTime", "Full chip erase 2^n m-sec"},
+};
+
+static long lpddr_get_qinforec_pos(struct map_info *map, char *id_str)
+{
+ int qinfo_lines = sizeof(qinfo_array)/sizeof(struct qinfo_query_info);
+ int i;
+ int bankwidth = map_bankwidth(map) * 8;
+ int major, minor;
+
+ for (i = 0; i < qinfo_lines; i++) {
+ if (strcmp(id_str, qinfo_array[i].id_str) == 0) {
+ major = qinfo_array[i].major & ((1 << bankwidth) - 1);
+ minor = qinfo_array[i].minor & ((1 << bankwidth) - 1);
+ return minor | (major << bankwidth);
+ }
+ }
+ printk(KERN_ERR"%s qinfo id string is wrong! \n", map->name);
+ BUG();
+ return -1;
+}
+
+static uint16_t lpddr_info_query(struct map_info *map, char *id_str)
+{
+ unsigned int dsr, val;
+ int bits_per_chip = map_bankwidth(map) * 8;
+ unsigned long adr = lpddr_get_qinforec_pos(map, id_str);
+ int attempts = 20;
+
+ /* Write a request for the PFOW record */
+ map_write(map, CMD(LPDDR_INFO_QUERY),
+ map->pfow_base + PFOW_COMMAND_CODE);
+ map_write(map, CMD(adr & ((1 << bits_per_chip) - 1)),
+ map->pfow_base + PFOW_COMMAND_ADDRESS_L);
+ map_write(map, CMD(adr >> bits_per_chip),
+ map->pfow_base + PFOW_COMMAND_ADDRESS_H);
+ map_write(map, CMD(LPDDR_START_EXECUTION),
+ map->pfow_base + PFOW_COMMAND_EXECUTE);
+
+ while ((attempts--) > 0) {
+ dsr = CMDVAL(map_read(map, map->pfow_base + PFOW_DSR));
+ if (dsr & DSR_READY_STATUS)
+ break;
+ udelay(10);
+ }
+
+ val = CMDVAL(map_read(map, map->pfow_base + PFOW_COMMAND_DATA));
+ return val;
+}
+
+static int lpddr_pfow_present(struct map_info *map, struct lpddr_private *lpddr)
+{
+ map_word pfow_val[4];
+
+ /* Check identification string */
+ pfow_val[0] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_P);
+ pfow_val[1] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_F);
+ pfow_val[2] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_O);
+ pfow_val[3] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_W);
+
+ if (!map_word_equal(map, CMD('P'), pfow_val[0]))
+ goto out;
+
+ if (!map_word_equal(map, CMD('F'), pfow_val[1]))
+ goto out;
+
+ if (!map_word_equal(map, CMD('O'), pfow_val[2]))
+ goto out;
+
+ if (!map_word_equal(map, CMD('W'), pfow_val[3]))
+ goto out;
+
+ return 1; /* "PFOW" is found */
+out:
+ printk(KERN_WARNING"%s: PFOW string at 0x%lx is not found \n",
+ map->name, map->pfow_base);
+ return 0;
+}
+
+static int lpddr_chip_setup(struct map_info *map, struct lpddr_private *lpddr)
+{
+
+ lpddr->qinfo = kmalloc(sizeof(struct qinfo_chip), GFP_KERNEL);
+ if (!lpddr->qinfo) {
+ printk(KERN_WARNING "%s: no memory for LPDDR qinfo structure\n",
+ map->name);
+ return 0;
+ }
+ memset(lpddr->qinfo, 0, sizeof(struct qinfo_chip));
+
+ /* Get the ManuID */
+ lpddr->ManufactId = CMDVAL(map_read(map, map->pfow_base + PFOW_MANUFACTURER_ID));
+ /* Get the DeviceID */
+ lpddr->DevId = CMDVAL(map_read(map, map->pfow_base + PFOW_DEVICE_ID));
+ /* read parameters from chip qinfo table */
+ lpddr->qinfo->DevSizeShift = lpddr_info_query(map, "DevSizeShift");
+ lpddr->qinfo->TotalBlocksNum = lpddr_info_query(map, "TotalBlocksNum");
+ lpddr->qinfo->BufSizeShift = lpddr_info_query(map, "BufSizeShift");
+ lpddr->qinfo->HWPartsNum = lpddr_info_query(map, "HWPartsNum");
+ lpddr->qinfo->UniformBlockSizeShift =
+ lpddr_info_query(map, "UniformBlockSizeShift");
+ lpddr->qinfo->SuspEraseSupp = lpddr_info_query(map, "SuspEraseSupp");
+ lpddr->qinfo->SingleWordProgTime =
+ lpddr_info_query(map, "SingleWordProgTime");
+ lpddr->qinfo->ProgBufferTime = lpddr_info_query(map, "ProgBufferTime");
+ lpddr->qinfo->BlockEraseTime = lpddr_info_query(map, "BlockEraseTime");
+ return 1;
+}
+static struct lpddr_private *lpddr_probe_chip(struct map_info *map)
+{
+ struct lpddr_private lpddr;
+ struct lpddr_private *retlpddr;
+ int numvirtchips;
+
+
+ if ((map->pfow_base + 0x1000) >= map->size) {
+ printk(KERN_NOTICE"%s Probe at base (0x%08lx) past the end of"
+ "the map(0x%08lx)\n", map->name,
+ (unsigned long)map->pfow_base, map->size - 1);
+ return NULL;
+ }
+ memset(&lpddr, 0, sizeof(struct lpddr_private));
+ if (!lpddr_pfow_present(map, &lpddr))
+ return NULL;
+
+ if (!lpddr_chip_setup(map, &lpddr))
+ return NULL;
+
+ /* Ok so we found a chip */
+ lpddr.chipshift = lpddr.qinfo->DevSizeShift;
+ lpddr.numchips = 1;
+
+ numvirtchips = lpddr.numchips * lpddr.qinfo->HWPartsNum;
+ retlpddr = kmalloc(sizeof(struct lpddr_private) +
+ numvirtchips * sizeof(struct flchip), GFP_KERNEL);
+ if (!retlpddr)
+ return NULL;
+
+ memset(retlpddr, 0, sizeof(struct lpddr_private) +
+ numvirtchips * sizeof(struct flchip));
+ memcpy(retlpddr, &lpddr, sizeof(struct lpddr_private));
+
+ retlpddr->numchips = numvirtchips;
+ retlpddr->chipshift = retlpddr->qinfo->DevSizeShift -
+ __ffs(retlpddr->qinfo->HWPartsNum);
+
+ return retlpddr;
+}
+
+struct mtd_info *lpddr_probe(struct map_info *map)
+{
+ struct mtd_info *mtd = NULL;
+ struct lpddr_private *lpddr;
+
+ /* First probe the map to see if we havecan open PFOW here */
+ lpddr = lpddr_probe_chip(map);
+ if (!lpddr)
+ return NULL;
+
+ map->fldrv_priv = lpddr;
+ mtd = lpddr_cmdset(map);
+ if (mtd) {
+ if (mtd->size > map->size) {
+ printk(KERN_WARNING "Reducing visibility of %ldKiB chip"
+ "to %ldKiB\n", (unsigned long)mtd->size >> 10,
+ (unsigned long)map->size >> 10);
+ mtd->size = map->size;
+ }
+ return mtd;
+ }
+
+ kfree(lpddr->qinfo);
+ kfree(lpddr);
+ map->fldrv_priv = NULL;
+ return NULL;
+}
+
+static struct mtd_chip_driver lpddr_chipdrv = {
+ .probe = lpddr_probe,
+ .name = "qinfo_probe",
+ .module = THIS_MODULE
+};
+
+static int __init lpddr_probe_init(void)
+{
+ register_mtd_chip_driver(&lpddr_chipdrv);
+ return 0;
+}
+
+static void __exit lpddr_probe_exit(void)
+{
+ unregister_mtd_chip_driver(&lpddr_chipdrv);
+}
+
+module_init(lpddr_probe_init);
+module_exit(lpddr_probe_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vasiliy Leonenko <vasiliy.leonenko@gmail.com>");
+MODULE_DESCRIPTION("Driver to probe qinfo flash chips");
+
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 5ea169362164..0225cbbf22de 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -10,8 +10,8 @@ config MTD_COMPLEX_MAPPINGS
paged mappings of flash chips.
config MTD_PHYSMAP
- tristate "CFI Flash device in physical memory map"
- depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM
+ tristate "Flash device in physical memory map"
+ depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM || MTD_LPDDR
help
This provides a 'mapping' driver which allows the NOR Flash and
ROM driver code to communicate with chips which are mapped
@@ -23,9 +23,20 @@ config MTD_PHYSMAP
To compile this driver as a module, choose M here: the
module will be called physmap.
+config MTD_PHYSMAP_COMPAT
+ bool "Physmap compat support"
+ depends on MTD_PHYSMAP
+ default n
+ help
+ Setup a simple mapping via the Kconfig options. Normally the
+ physmap configuration options are done via your board's
+ resource file.
+
+ If unsure, say N here.
+
config MTD_PHYSMAP_START
hex "Physical start address of flash mapping"
- depends on MTD_PHYSMAP
+ depends on MTD_PHYSMAP_COMPAT
default "0x8000000"
help
This is the physical memory location at which the flash chips
@@ -37,7 +48,7 @@ config MTD_PHYSMAP_START
config MTD_PHYSMAP_LEN
hex "Physical length of flash mapping"
- depends on MTD_PHYSMAP
+ depends on MTD_PHYSMAP_COMPAT
default "0"
help
This is the total length of the mapping of the flash chips on
@@ -51,7 +62,7 @@ config MTD_PHYSMAP_LEN
config MTD_PHYSMAP_BANKWIDTH
int "Bank width in octets"
- depends on MTD_PHYSMAP
+ depends on MTD_PHYSMAP_COMPAT
default "2"
help
This is the total width of the data bus of the flash devices
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c
index 82811bcb0436..845ad4f2a542 100644
--- a/drivers/mtd/maps/alchemy-flash.c
+++ b/drivers/mtd/maps/alchemy-flash.c
@@ -111,7 +111,7 @@ static struct mtd_partition alchemy_partitions[] = {
static struct mtd_info *mymtd;
-int __init alchemy_mtd_init(void)
+static int __init alchemy_mtd_init(void)
{
struct mtd_partition *parts;
int nb_parts = 0;
diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c
index d1eec7d3243f..237733d094c4 100644
--- a/drivers/mtd/maps/amd76xrom.c
+++ b/drivers/mtd/maps/amd76xrom.c
@@ -232,8 +232,8 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
/* Trim the size if we are larger than the map */
if (map->mtd->size > map->map.size) {
printk(KERN_WARNING MOD_NAME
- " rom(%u) larger than window(%lu). fixing...\n",
- map->mtd->size, map->map.size);
+ " rom(%llu) larger than window(%lu). fixing...\n",
+ (unsigned long long)map->mtd->size, map->map.size);
map->mtd->size = map->map.size;
}
if (window->rsrc.parent) {
diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c
index 0ecc3f6d735b..b4ed81611918 100644
--- a/drivers/mtd/maps/cfi_flagadm.c
+++ b/drivers/mtd/maps/cfi_flagadm.c
@@ -88,7 +88,7 @@ struct mtd_partition flagadm_parts[] = {
static struct mtd_info *mymtd;
-int __init init_flagadm(void)
+static int __init init_flagadm(void)
{
printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n",
FLASH_SIZE, FLASH_PHYS_ADDR);
diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c
index 1a6feb4474de..5f7a245ed132 100644
--- a/drivers/mtd/maps/ck804xrom.c
+++ b/drivers/mtd/maps/ck804xrom.c
@@ -263,8 +263,8 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
/* Trim the size if we are larger than the map */
if (map->mtd->size > map->map.size) {
printk(KERN_WARNING MOD_NAME
- " rom(%u) larger than window(%lu). fixing...\n",
- map->mtd->size, map->map.size);
+ " rom(%llu) larger than window(%lu). fixing...\n",
+ (unsigned long long)map->mtd->size, map->map.size);
map->mtd->size = map->map.size;
}
if (window->rsrc.parent) {
diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c
index e115667bf1d0..cfacfa6f45dd 100644
--- a/drivers/mtd/maps/dbox2-flash.c
+++ b/drivers/mtd/maps/dbox2-flash.c
@@ -69,7 +69,7 @@ struct map_info dbox2_flash_map = {
.phys = WINDOW_ADDR,
};
-int __init init_dbox2_flash(void)
+static int __init init_dbox2_flash(void)
{
printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR);
dbox2_flash_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c
index 9433738c1664..be9e90b44587 100644
--- a/drivers/mtd/maps/edb7312.c
+++ b/drivers/mtd/maps/edb7312.c
@@ -71,7 +71,7 @@ static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
static int mtd_parts_nb = 0;
static struct mtd_partition *mtd_parts = 0;
-int __init init_edb7312nor(void)
+static int __init init_edb7312nor(void)
{
static const char *rom_probe_types[] = PROBETYPES;
const char **type;
diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c
index bbbcdd4c8d13..11a2f57df9cf 100644
--- a/drivers/mtd/maps/esb2rom.c
+++ b/drivers/mtd/maps/esb2rom.c
@@ -324,8 +324,8 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev,
/* Trim the size if we are larger than the map */
if (map->mtd->size > map->map.size) {
printk(KERN_WARNING MOD_NAME
- " rom(%u) larger than window(%lu). fixing...\n",
- map->mtd->size, map->map.size);
+ " rom(%llu) larger than window(%lu). fixing...\n",
+ (unsigned long long)map->mtd->size, map->map.size);
map->mtd->size = map->map.size;
}
if (window->rsrc.parent) {
diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c
index a8e3fde4cbd5..1e43124d498b 100644
--- a/drivers/mtd/maps/fortunet.c
+++ b/drivers/mtd/maps/fortunet.c
@@ -181,7 +181,7 @@ __setup("MTD_Partition=", MTD_New_Partition);
/* Backwards-spelling-compatibility */
__setup("MTD_Partion=", MTD_New_Partition);
-int __init init_fortunet(void)
+static int __init init_fortunet(void)
{
int ix,iy;
for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++)
diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c
index 3b959fad1c4e..72c724fa8c27 100644
--- a/drivers/mtd/maps/h720x-flash.c
+++ b/drivers/mtd/maps/h720x-flash.c
@@ -65,7 +65,7 @@ static const char *probes[] = { "cmdlinepart", NULL };
/*
* Initialize FLASH support
*/
-int __init h720x_mtd_init(void)
+static int __init h720x_mtd_init(void)
{
char *part_type = NULL;
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
index aeb6c916e23f..c32bc28920b3 100644
--- a/drivers/mtd/maps/ichxrom.c
+++ b/drivers/mtd/maps/ichxrom.c
@@ -258,8 +258,8 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
/* Trim the size if we are larger than the map */
if (map->mtd->size > map->map.size) {
printk(KERN_WARNING MOD_NAME
- " rom(%u) larger than window(%lu). fixing...\n",
- map->mtd->size, map->map.size);
+ " rom(%llu) larger than window(%lu). fixing...\n",
+ (unsigned long long)map->mtd->size, map->map.size);
map->mtd->size = map->map.size;
}
if (window->rsrc.parent) {
diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c
index 2682ab51a367..998a27da97f3 100644
--- a/drivers/mtd/maps/impa7.c
+++ b/drivers/mtd/maps/impa7.c
@@ -70,7 +70,7 @@ static struct mtd_partition *mtd_parts[NUM_FLASHBANKS];
static const char *probes[] = { "cmdlinepart", NULL };
-int __init init_impa7(void)
+static int __init init_impa7(void)
{
static const char *rom_probe_types[] = PROBETYPES;
const char **type;
diff --git a/drivers/mtd/maps/ipaq-flash.c b/drivers/mtd/maps/ipaq-flash.c
index ed58f6a77bd9..748c85f635f1 100644
--- a/drivers/mtd/maps/ipaq-flash.c
+++ b/drivers/mtd/maps/ipaq-flash.c
@@ -202,7 +202,7 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
static int __init h1900_special_case(void);
-int __init ipaq_mtd_init(void)
+static int __init ipaq_mtd_init(void)
{
struct mtd_partition *parts = NULL;
int nb_parts = 0;
diff --git a/drivers/mtd/maps/mbx860.c b/drivers/mtd/maps/mbx860.c
index 706f67394b07..0eb5a7c85380 100644
--- a/drivers/mtd/maps/mbx860.c
+++ b/drivers/mtd/maps/mbx860.c
@@ -55,7 +55,7 @@ struct map_info mbx_map = {
.bankwidth = 4,
};
-int __init init_mbx(void)
+static int __init init_mbx(void)
{
printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR);
mbx_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
index 965e6c6d6ab0..a97133eb9d70 100644
--- a/drivers/mtd/maps/nettel.c
+++ b/drivers/mtd/maps/nettel.c
@@ -226,7 +226,7 @@ static int __init nettel_init(void)
if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) {
printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n",
- amd_mtd->size>>10);
+ (int)(amd_mtd->size>>10));
amd_mtd->owner = THIS_MODULE;
@@ -357,13 +357,12 @@ static int __init nettel_init(void)
*intel1par = 0;
}
- printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n",
- (intel_mtd->size >> 10));
+ printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %lldKiB\n",
+ (unsigned long long)(intel_mtd->size >> 10));
intel_mtd->owner = THIS_MODULE;
- num_intel_partitions = sizeof(nettel_intel_partitions) /
- sizeof(nettel_intel_partitions[0]);
+ num_intel_partitions = ARRAY_SIZE(nettel_intel_partitions);
if (intelboot) {
/*
diff --git a/drivers/mtd/maps/octagon-5066.c b/drivers/mtd/maps/octagon-5066.c
index 43e04c1d22a9..2b2e45093218 100644
--- a/drivers/mtd/maps/octagon-5066.c
+++ b/drivers/mtd/maps/octagon-5066.c
@@ -184,7 +184,7 @@ void cleanup_oct5066(void)
release_region(PAGE_IO, 1);
}
-int __init init_oct5066(void)
+static int __init init_oct5066(void)
{
int i;
int ret = 0;
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index 1db16e549e38..87743661d48e 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -29,7 +29,6 @@ struct physmap_flash_info {
struct map_info map[MAX_RESOURCES];
#ifdef CONFIG_MTD_PARTITIONS
int nr_parts;
- struct mtd_partition *parts;
#endif
};
@@ -56,14 +55,10 @@ static int physmap_flash_remove(struct platform_device *dev)
for (i = 0; i < MAX_RESOURCES; i++) {
if (info->mtd[i] != NULL) {
#ifdef CONFIG_MTD_PARTITIONS
- if (info->nr_parts) {
+ if (info->nr_parts || physmap_data->nr_parts)
del_mtd_partitions(info->mtd[i]);
- kfree(info->parts);
- } else if (physmap_data->nr_parts) {
- del_mtd_partitions(info->mtd[i]);
- } else {
+ else
del_mtd_device(info->mtd[i]);
- }
#else
del_mtd_device(info->mtd[i]);
#endif
@@ -73,7 +68,12 @@ static int physmap_flash_remove(struct platform_device *dev)
return 0;
}
-static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
+static const char *rom_probe_types[] = {
+ "cfi_probe",
+ "jedec_probe",
+ "qinfo_probe",
+ "map_rom",
+ NULL };
#ifdef CONFIG_MTD_PARTITIONS
static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
#endif
@@ -86,6 +86,9 @@ static int physmap_flash_probe(struct platform_device *dev)
int err = 0;
int i;
int devices_found = 0;
+#ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *parts;
+#endif
physmap_data = dev->dev.platform_data;
if (physmap_data == NULL)
@@ -119,6 +122,7 @@ static int physmap_flash_probe(struct platform_device *dev)
info->map[i].size = dev->resource[i].end - dev->resource[i].start + 1;
info->map[i].bankwidth = physmap_data->width;
info->map[i].set_vpp = physmap_data->set_vpp;
+ info->map[i].pfow_base = physmap_data->pfow_base;
info->map[i].virt = devm_ioremap(&dev->dev, info->map[i].phys,
info->map[i].size);
@@ -163,9 +167,10 @@ static int physmap_flash_probe(struct platform_device *dev)
goto err_out;
#ifdef CONFIG_MTD_PARTITIONS
- err = parse_mtd_partitions(info->cmtd, part_probe_types, &info->parts, 0);
+ err = parse_mtd_partitions(info->cmtd, part_probe_types, &parts, 0);
if (err > 0) {
- add_mtd_partitions(info->cmtd, info->parts, err);
+ add_mtd_partitions(info->cmtd, parts, err);
+ kfree(parts);
return 0;
}
@@ -251,14 +256,7 @@ static struct platform_driver physmap_flash_driver = {
};
-#ifdef CONFIG_MTD_PHYSMAP_LEN
-#if CONFIG_MTD_PHYSMAP_LEN != 0
-#warning using PHYSMAP compat code
-#define PHYSMAP_COMPAT
-#endif
-#endif
-
-#ifdef PHYSMAP_COMPAT
+#ifdef CONFIG_MTD_PHYSMAP_COMPAT
static struct physmap_flash_data physmap_flash_data = {
.width = CONFIG_MTD_PHYSMAP_BANKWIDTH,
};
@@ -302,7 +300,7 @@ static int __init physmap_init(void)
int err;
err = platform_driver_register(&physmap_flash_driver);
-#ifdef PHYSMAP_COMPAT
+#ifdef CONFIG_MTD_PHYSMAP_COMPAT
if (err == 0)
platform_device_register(&physmap_flash);
#endif
@@ -312,7 +310,7 @@ static int __init physmap_init(void)
static void __exit physmap_exit(void)
{
-#ifdef PHYSMAP_COMPAT
+#ifdef CONFIG_MTD_PHYSMAP_COMPAT
platform_device_unregister(&physmap_flash);
#endif
platform_driver_unregister(&physmap_flash_driver);
@@ -326,8 +324,7 @@ MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
MODULE_DESCRIPTION("Generic configurable MTD map driver");
/* legacy platform drivers can't hotplug or coldplg */
-#ifndef PHYSMAP_COMPAT
+#ifndef CONFIG_MTD_PHYSMAP_COMPAT
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:physmap-flash");
#endif
-
diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c
index f43ba2815cbb..4768bd5459d6 100644
--- a/drivers/mtd/maps/pmcmsp-flash.c
+++ b/drivers/mtd/maps/pmcmsp-flash.c
@@ -48,7 +48,7 @@ static int fcnt;
#define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n", __func__, __LINE__)
-int __init init_msp_flash(void)
+static int __init init_msp_flash(void)
{
int i, j;
int offset, coff;
diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c
index de002eb1a7fe..933c0b63b016 100644
--- a/drivers/mtd/maps/redwood.c
+++ b/drivers/mtd/maps/redwood.c
@@ -122,7 +122,7 @@ struct map_info redwood_flash_map = {
static struct mtd_info *redwood_mtd;
-int __init init_redwood_flash(void)
+static int __init init_redwood_flash(void)
{
int err;
diff --git a/drivers/mtd/maps/rpxlite.c b/drivers/mtd/maps/rpxlite.c
index 14d90edb4430..3e3ef53d4fd4 100644
--- a/drivers/mtd/maps/rpxlite.c
+++ b/drivers/mtd/maps/rpxlite.c
@@ -23,7 +23,7 @@ static struct map_info rpxlite_map = {
.phys = WINDOW_ADDR,
};
-int __init init_rpxlite(void)
+static int __init init_rpxlite(void)
{
printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR);
rpxlite_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c
index 6e1e99cd2b59..d5374cdcb163 100644
--- a/drivers/mtd/maps/sbc8240.c
+++ b/drivers/mtd/maps/sbc8240.c
@@ -136,7 +136,7 @@ static struct mtd_part_def sbc8240_part_banks[NUM_FLASH_BANKS];
#endif /* CONFIG_MTD_PARTITIONS */
-int __init init_sbc8240_mtd (void)
+static int __init init_sbc8240_mtd (void)
{
static struct _cjs {
u_long addr;
diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c
index 21169e6d646c..7e329f09a548 100644
--- a/drivers/mtd/maps/scb2_flash.c
+++ b/drivers/mtd/maps/scb2_flash.c
@@ -118,7 +118,8 @@ scb2_fixup_mtd(struct mtd_info *mtd)
struct mtd_erase_region_info *region = &mtd->eraseregions[i];
if (region->numblocks * region->erasesize > mtd->size) {
- region->numblocks = (mtd->size / region->erasesize);
+ region->numblocks = ((unsigned long)mtd->size /
+ region->erasesize);
done = 1;
} else {
region->numblocks = 0;
@@ -187,8 +188,9 @@ scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
return -ENODEV;
}
- printk(KERN_NOTICE MODNAME ": chip size 0x%x at offset 0x%x\n",
- scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size);
+ printk(KERN_NOTICE MODNAME ": chip size 0x%llx at offset 0x%llx\n",
+ (unsigned long long)scb2_mtd->size,
+ (unsigned long long)(SCB2_WINDOW - scb2_mtd->size));
add_mtd_device(scb2_mtd);
diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c
index 026eab028189..b392f096c706 100644
--- a/drivers/mtd/maps/sharpsl-flash.c
+++ b/drivers/mtd/maps/sharpsl-flash.c
@@ -47,7 +47,7 @@ static struct mtd_partition sharpsl_partitions[1] = {
}
};
-int __init init_sharpsl(void)
+static int __init init_sharpsl(void)
{
struct mtd_partition *parts;
int nb_parts = 0;
diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c
index a5d3d8531faa..60146984f4be 100644
--- a/drivers/mtd/maps/tqm8xxl.c
+++ b/drivers/mtd/maps/tqm8xxl.c
@@ -109,7 +109,7 @@ static struct mtd_partition tqm8xxl_fs_partitions[] = {
};
#endif
-int __init init_tqm_mtd(void)
+static int __init init_tqm_mtd(void)
{
int idx = 0, ret = 0;
unsigned long flash_addr, flash_size, mtd_size = 0;
diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c
index 0dc645f8152f..81756e397711 100644
--- a/drivers/mtd/maps/uclinux.c
+++ b/drivers/mtd/maps/uclinux.c
@@ -51,7 +51,7 @@ int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len,
/****************************************************************************/
-int __init uclinux_mtd_init(void)
+static int __init uclinux_mtd_init(void)
{
struct mtd_info *mtd;
struct map_info *mapp;
@@ -94,7 +94,7 @@ int __init uclinux_mtd_init(void)
/****************************************************************************/
-void __exit uclinux_mtd_cleanup(void)
+static void __exit uclinux_mtd_cleanup(void)
{
if (uclinux_ram_mtdinfo) {
del_mtd_partitions(uclinux_ram_mtdinfo);
diff --git a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c
index 5a0c9a353b0f..6d452dcdfe34 100644
--- a/drivers/mtd/maps/vmax301.c
+++ b/drivers/mtd/maps/vmax301.c
@@ -146,7 +146,7 @@ static void __exit cleanup_vmax301(void)
iounmap((void *)vmax_map[0].map_priv_1 - WINDOW_START);
}
-int __init init_vmax301(void)
+static int __init init_vmax301(void)
{
int i;
unsigned long iomapadr;
diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c
index 413b0cf9bbd2..933a2b6598b4 100644
--- a/drivers/mtd/maps/wr_sbc82xx_flash.c
+++ b/drivers/mtd/maps/wr_sbc82xx_flash.c
@@ -74,7 +74,7 @@ do { \
} \
} while (0);
-int __init init_sbc82xx_flash(void)
+static int __init init_sbc82xx_flash(void)
{
volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
int bigflash;
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index bcffeda2df3d..e9ec59e9a566 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -450,16 +450,20 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if (!erase)
ret = -ENOMEM;
else {
+ struct erase_info_user einfo;
+
wait_queue_head_t waitq;
DECLARE_WAITQUEUE(wait, current);
init_waitqueue_head(&waitq);
- if (copy_from_user(&erase->addr, argp,
+ if (copy_from_user(&einfo, argp,
sizeof(struct erase_info_user))) {
kfree(erase);
return -EFAULT;
}
+ erase->addr = einfo.start;
+ erase->len = einfo.length;
erase->mtd = mtd;
erase->callback = mtdchar_erase_callback;
erase->priv = (unsigned long)&waitq;
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 1a05cf37851e..3dbb1b38db66 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -197,7 +197,7 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
continue;
}
- size = min(total_len, (size_t)(subdev->size - to));
+ size = min_t(uint64_t, total_len, subdev->size - to);
wsize = size; /* store for future use */
entry_high = entry_low;
@@ -385,7 +385,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
struct mtd_concat *concat = CONCAT(mtd);
struct mtd_info *subdev;
int i, err;
- u_int32_t length, offset = 0;
+ uint64_t length, offset = 0;
struct erase_info *erase;
if (!(mtd->flags & MTD_WRITEABLE))
@@ -518,7 +518,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
return 0;
}
-static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct mtd_concat *concat = CONCAT(mtd);
int i, err = -EINVAL;
@@ -528,7 +528,7 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
- size_t size;
+ uint64_t size;
if (ofs >= subdev->size) {
size = 0;
@@ -556,7 +556,7 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
return err;
}
-static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct mtd_concat *concat = CONCAT(mtd);
int i, err = 0;
@@ -566,7 +566,7 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
- size_t size;
+ uint64_t size;
if (ofs >= subdev->size) {
size = 0;
@@ -696,7 +696,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
int i;
size_t size;
struct mtd_concat *concat;
- u_int32_t max_erasesize, curr_erasesize;
+ uint32_t max_erasesize, curr_erasesize;
int num_erase_region;
printk(KERN_NOTICE "Concatenating MTD devices:\n");
@@ -842,12 +842,14 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.erasesize = curr_erasesize;
concat->mtd.numeraseregions = 0;
} else {
+ uint64_t tmp64;
+
/*
* erase block size varies across the subdevices: allocate
* space to store the data describing the variable erase regions
*/
struct mtd_erase_region_info *erase_region_p;
- u_int32_t begin, position;
+ uint64_t begin, position;
concat->mtd.erasesize = max_erasesize;
concat->mtd.numeraseregions = num_erase_region;
@@ -879,8 +881,9 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
erase_region_p->offset = begin;
erase_region_p->erasesize =
curr_erasesize;
- erase_region_p->numblocks =
- (position - begin) / curr_erasesize;
+ tmp64 = position - begin;
+ do_div(tmp64, curr_erasesize);
+ erase_region_p->numblocks = tmp64;
begin = position;
curr_erasesize = subdev[i]->erasesize;
@@ -897,9 +900,9 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
erase_region_p->offset = begin;
erase_region_p->erasesize =
curr_erasesize;
- erase_region_p->numblocks =
- (position -
- begin) / curr_erasesize;
+ tmp64 = position - begin;
+ do_div(tmp64, curr_erasesize);
+ erase_region_p->numblocks = tmp64;
begin = position;
curr_erasesize =
@@ -909,14 +912,16 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
}
position +=
subdev[i]->eraseregions[j].
- numblocks * curr_erasesize;
+ numblocks * (uint64_t)curr_erasesize;
}
}
}
/* Now write the final entry */
erase_region_p->offset = begin;
erase_region_p->erasesize = curr_erasesize;
- erase_region_p->numblocks = (position - begin) / curr_erasesize;
+ tmp64 = position - begin;
+ do_div(tmp64, curr_erasesize);
+ erase_region_p->numblocks = tmp64;
}
return &concat->mtd;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index a9d246949820..76fe0a1e7a5e 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -57,6 +57,19 @@ int add_mtd_device(struct mtd_info *mtd)
mtd->index = i;
mtd->usecount = 0;
+ if (is_power_of_2(mtd->erasesize))
+ mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
+ else
+ mtd->erasesize_shift = 0;
+
+ if (is_power_of_2(mtd->writesize))
+ mtd->writesize_shift = ffs(mtd->writesize) - 1;
+ else
+ mtd->writesize_shift = 0;
+
+ mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
+ mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
+
/* Some chips always power up locked. Unlock them now */
if ((mtd->flags & MTD_WRITEABLE)
&& (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) {
@@ -344,7 +357,8 @@ static inline int mtd_proc_info (char *buf, int i)
if (!this)
return 0;
- return sprintf(buf, "mtd%d: %8.8x %8.8x \"%s\"\n", i, this->size,
+ return sprintf(buf, "mtd%d: %8.8llx %8.8x \"%s\"\n", i,
+ (unsigned long long)this->size,
this->erasesize, this->name);
}
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index aebb3b27edbd..1a6b3beabe8d 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -80,9 +80,9 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
if (ret) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&wait_q, &wait);
- printk (KERN_WARNING "mtdoops: erase of region [0x%x, 0x%x] "
+ printk (KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] "
"on \"%s\" failed\n",
- erase.addr, erase.len, mtd->name);
+ (unsigned long long)erase.addr, (unsigned long long)erase.len, mtd->name);
return ret;
}
@@ -289,7 +289,10 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
}
cxt->mtd = mtd;
- cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE;
+ if (mtd->size > INT_MAX)
+ cxt->oops_pages = INT_MAX / OOPS_PAGE_SIZE;
+ else
+ cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE;
find_next_position(cxt);
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 3728913fa5fa..144e6b613a77 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -26,7 +26,7 @@ static LIST_HEAD(mtd_partitions);
struct mtd_part {
struct mtd_info mtd;
struct mtd_info *master;
- u_int32_t offset;
+ uint64_t offset;
int index;
struct list_head list;
int registered;
@@ -235,7 +235,7 @@ void mtd_erase_callback(struct erase_info *instr)
}
EXPORT_SYMBOL_GPL(mtd_erase_callback);
-static int part_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct mtd_part *part = PART(mtd);
if ((len + ofs) > mtd->size)
@@ -243,7 +243,7 @@ static int part_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
return part->master->lock(part->master, ofs + part->offset, len);
}
-static int part_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct mtd_part *part = PART(mtd);
if ((len + ofs) > mtd->size)
@@ -317,7 +317,7 @@ EXPORT_SYMBOL(del_mtd_partitions);
static struct mtd_part *add_one_partition(struct mtd_info *master,
const struct mtd_partition *part, int partno,
- u_int32_t cur_offset)
+ uint64_t cur_offset)
{
struct mtd_part *slave;
@@ -395,19 +395,19 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
slave->offset = cur_offset;
if (slave->offset == MTDPART_OFS_NXTBLK) {
slave->offset = cur_offset;
- if ((cur_offset % master->erasesize) != 0) {
+ if (mtd_mod_by_eb(cur_offset, master) != 0) {
/* Round up to next erasesize */
- slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize;
+ slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
printk(KERN_NOTICE "Moving partition %d: "
- "0x%08x -> 0x%08x\n", partno,
- cur_offset, slave->offset);
+ "0x%012llx -> 0x%012llx\n", partno,
+ (unsigned long long)cur_offset, (unsigned long long)slave->offset);
}
}
if (slave->mtd.size == MTDPART_SIZ_FULL)
slave->mtd.size = master->size - slave->offset;
- printk(KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,
- slave->offset + slave->mtd.size, slave->mtd.name);
+ printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset,
+ (unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name);
/* let's do some sanity checks */
if (slave->offset >= master->size) {
@@ -420,13 +420,13 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
}
if (slave->offset + slave->mtd.size > master->size) {
slave->mtd.size = master->size - slave->offset;
- printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n",
- part->name, master->name, slave->mtd.size);
+ printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n",
+ part->name, master->name, (unsigned long long)slave->mtd.size);
}
if (master->numeraseregions > 1) {
/* Deal with variable erase size stuff */
int i, max = master->numeraseregions;
- u32 end = slave->offset + slave->mtd.size;
+ u64 end = slave->offset + slave->mtd.size;
struct mtd_erase_region_info *regions = master->eraseregions;
/* Find the first erase regions which is part of this
@@ -449,7 +449,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
}
if ((slave->mtd.flags & MTD_WRITEABLE) &&
- (slave->offset % slave->mtd.erasesize)) {
+ mtd_mod_by_eb(slave->offset, &slave->mtd)) {
/* Doesn't start on a boundary of major erase size */
/* FIXME: Let it be writable if it is on a boundary of
* _minor_ erase size though */
@@ -458,7 +458,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
part->name);
}
if ((slave->mtd.flags & MTD_WRITEABLE) &&
- (slave->mtd.size % slave->mtd.erasesize)) {
+ mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
slave->mtd.flags &= ~MTD_WRITEABLE;
printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
part->name);
@@ -466,7 +466,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
slave->mtd.ecclayout = master->ecclayout;
if (master->block_isbad) {
- uint32_t offs = 0;
+ uint64_t offs = 0;
while (offs < slave->mtd.size) {
if (master->block_isbad(master,
@@ -501,7 +501,7 @@ int add_mtd_partitions(struct mtd_info *master,
int nbparts)
{
struct mtd_part *slave;
- u_int32_t cur_offset = 0;
+ uint64_t cur_offset = 0;
int i;
printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index f8ae0400c49c..8b12e6e109d3 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -163,6 +163,13 @@ config MTD_NAND_S3C2410_HWECC
incorrect ECC generation, and if using these, the default of
software ECC is preferable.
+config MTD_NAND_NDFC
+ tristate "NDFC NanD Flash Controller"
+ depends on 4xx
+ select MTD_NAND_ECC_SMC
+ help
+ NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
+
config MTD_NAND_S3C2410_CLKSTOP
bool "S3C2410 NAND IDLE clock stop"
depends on MTD_NAND_S3C2410
diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c
index 962380394855..6d9649159a18 100644
--- a/drivers/mtd/nand/alauda.c
+++ b/drivers/mtd/nand/alauda.c
@@ -676,11 +676,11 @@ static int alauda_probe(struct usb_interface *interface,
goto error;
al->write_out = usb_sndbulkpipe(al->dev,
- ep_wr->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ usb_endpoint_num(ep_wr));
al->bulk_in = usb_rcvbulkpipe(al->dev,
- ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ usb_endpoint_num(ep_in));
al->bulk_out = usb_sndbulkpipe(al->dev,
- ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ usb_endpoint_num(ep_out));
/* second device is identical up to now */
memcpy(al+1, al, sizeof(*al));
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index b8064bf3aee4..22a6b2e50e91 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -90,7 +90,7 @@ static int timing[3];
module_param_array(timing, int, &numtimings, 0644);
#ifdef CONFIG_MTD_PARTITIONS
-static const char *part_probes[] = { "RedBoot", NULL };
+static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
#endif
/* Hrm. Why isn't this already conditional on something in the struct device? */
@@ -805,10 +805,13 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
add_mtd_device(mtd);
#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ mtd->name = "cafe_nand";
+#endif
nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0);
if (nr_parts > 0) {
cafe->parts = parts;
- dev_info(&cafe->pdev->dev, "%d RedBoot partitions found\n", nr_parts);
+ dev_info(&cafe->pdev->dev, "%d partitions found\n", nr_parts);
add_mtd_partitions(mtd, parts, nr_parts);
}
#endif
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 4aa5bd6158da..65929db29446 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -777,7 +777,9 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
/* Fill in fsl_elbc_mtd structure */
priv->mtd.priv = chip;
priv->mtd.owner = THIS_MODULE;
- priv->fmr = 0; /* rest filled in later */
+
+ /* Set the ECCM according to the settings in bootloader.*/
+ priv->fmr = in_be32(&lbc->fmr) & FMR_ECCM;
/* fill in nand_chip structure */
/* set up function call table */
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 0a9c9cd33f96..0c3afccde8a2 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2014,13 +2014,14 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
int allowbbt)
{
- int page, len, status, pages_per_block, ret, chipnr;
+ int page, status, pages_per_block, ret, chipnr;
struct nand_chip *chip = mtd->priv;
- int rewrite_bbt[NAND_MAX_CHIPS]={0};
+ loff_t rewrite_bbt[NAND_MAX_CHIPS]={0};
unsigned int bbt_masked_page = 0xffffffff;
+ loff_t len;
- DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",
- (unsigned int)instr->addr, (unsigned int)instr->len);
+ DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%012llx, len = %llu\n",
+ (unsigned long long)instr->addr, (unsigned long long)instr->len);
/* Start address must align on block boundary */
if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
@@ -2116,7 +2117,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
"Failed erase, page 0x%08x\n", page);
instr->state = MTD_ERASE_FAILED;
- instr->fail_addr = (page << chip->page_shift);
+ instr->fail_addr =
+ ((loff_t)page << chip->page_shift);
goto erase_exit;
}
@@ -2126,7 +2128,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
*/
if (bbt_masked_page != 0xffffffff &&
(page & BBT_PAGE_MASK) == bbt_masked_page)
- rewrite_bbt[chipnr] = (page << chip->page_shift);
+ rewrite_bbt[chipnr] =
+ ((loff_t)page << chip->page_shift);
/* Increment page address and decrement length */
len -= (1 << chip->phys_erase_shift);
@@ -2173,7 +2176,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
continue;
/* update the BBT for chip */
DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt "
- "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
+ "(%d:0x%0llx 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
chip->bbt_td->pages[chipnr]);
nand_update_bbt(mtd, rewrite_bbt[chipnr]);
}
@@ -2365,7 +2368,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
if (!mtd->name)
mtd->name = type->name;
- chip->chipsize = type->chipsize << 20;
+ chip->chipsize = (uint64_t)type->chipsize << 20;
/* Newer devices have all the information in additional id bytes */
if (!type->pagesize) {
@@ -2423,7 +2426,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
chip->bbt_erase_shift = chip->phys_erase_shift =
ffs(mtd->erasesize) - 1;
- chip->chip_shift = ffs(chip->chipsize) - 1;
+ if (chip->chipsize & 0xffffffff)
+ chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
+ else
+ chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1;
/* Set the bad block position */
chip->badblockpos = mtd->writesize > 512 ?
@@ -2517,7 +2523,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
/**
* nand_scan_tail - [NAND Interface] Scan for the NAND device
* @mtd: MTD device structure
- * @maxchips: Number of chips to scan for
*
* This is the second phase of the normal nand_scan() function. It
* fills out all the uninitialized function pointers with the defaults
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 0b1c48595f12..55c23e5cd210 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -171,16 +171,16 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
if (tmp == msk)
continue;
if (reserved_block_code && (tmp == reserved_block_code)) {
- printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n",
- ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+ printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n",
+ (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
mtd->ecc_stats.bbtblocks++;
continue;
}
/* Leave it for now, if its matured we can move this
* message to MTD_DEBUG_LEVEL0 */
- printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n",
- ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+ printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n",
+ (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
/* Factory marked bad or worn out ? */
if (tmp == 0)
this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
@@ -284,7 +284,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
/* Read the primary version, if available */
if (td->options & NAND_BBT_VERSION) {
- scan_read_raw(mtd, buf, td->pages[0] << this->page_shift,
+ scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
mtd->writesize);
td->version[0] = buf[mtd->writesize + td->veroffs];
printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
@@ -293,7 +293,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
/* Read the mirror version, if available */
if (md && (md->options & NAND_BBT_VERSION)) {
- scan_read_raw(mtd, buf, md->pages[0] << this->page_shift,
+ scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
mtd->writesize);
md->version[0] = buf[mtd->writesize + md->veroffs];
printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
@@ -411,7 +411,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
startblock = chip * numblocks;
numblocks += startblock;
- from = startblock << (this->bbt_erase_shift - 1);
+ from = (loff_t)startblock << (this->bbt_erase_shift - 1);
}
for (i = startblock; i < numblocks;) {
@@ -428,8 +428,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
if (ret) {
this->bbt[i >> 3] |= 0x03 << (i & 0x6);
- printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
- i >> 1, (unsigned int)from);
+ printk(KERN_WARNING "Bad eraseblock %d at 0x%012llx\n",
+ i >> 1, (unsigned long long)from);
mtd->ecc_stats.badblocks++;
}
@@ -495,7 +495,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
for (block = 0; block < td->maxblocks; block++) {
int actblock = startblock + dir * block;
- loff_t offs = actblock << this->bbt_erase_shift;
+ loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
/* Read first page */
scan_read_raw(mtd, buf, offs, mtd->writesize);
@@ -719,7 +719,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
memset(&einfo, 0, sizeof(einfo));
einfo.mtd = mtd;
- einfo.addr = (unsigned long)to;
+ einfo.addr = to;
einfo.len = 1 << this->bbt_erase_shift;
res = nand_erase_nand(mtd, &einfo, 1);
if (res < 0)
@@ -729,8 +729,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
if (res < 0)
goto outerr;
- printk(KERN_DEBUG "Bad block table written to 0x%08x, version "
- "0x%02X\n", (unsigned int)to, td->version[chip]);
+ printk(KERN_DEBUG "Bad block table written to 0x%012llx, version "
+ "0x%02X\n", (unsigned long long)to, td->version[chip]);
/* Mark it as used */
td->pages[chip] = page;
@@ -910,7 +910,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
newval = oldval | (0x2 << (block & 0x06));
this->bbt[(block >> 3)] = newval;
if ((oldval != newval) && td->reserved_block_code)
- nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1));
+ nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));
continue;
}
update = 0;
@@ -931,7 +931,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
new ones have been marked, then we need to update the stored
bbts. This should only happen once. */
if (update && td->reserved_block_code)
- nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1));
+ nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));
}
}
@@ -1027,7 +1027,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
if (!this->bbt || !td)
return -EINVAL;
- len = mtd->size >> (this->bbt_erase_shift + 2);
/* Allocate a temporary buffer for one eraseblock incl. oob */
len = (1 << this->bbt_erase_shift);
len += (len >> this->page_shift) * mtd->oobsize;
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index ae7c57781a68..cd0711b83ac4 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -38,6 +38,9 @@
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
/* Default simulator parameters values */
#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \
@@ -100,6 +103,7 @@ static unsigned int bitflips = 0;
static char *gravepages = NULL;
static unsigned int rptwear = 0;
static unsigned int overridesize = 0;
+static char *cache_file = NULL;
module_param(first_id_byte, uint, 0400);
module_param(second_id_byte, uint, 0400);
@@ -122,12 +126,13 @@ module_param(bitflips, uint, 0400);
module_param(gravepages, charp, 0400);
module_param(rptwear, uint, 0400);
module_param(overridesize, uint, 0400);
+module_param(cache_file, charp, 0400);
MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)");
MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command");
MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command");
-MODULE_PARM_DESC(access_delay, "Initial page access delay (microiseconds)");
+MODULE_PARM_DESC(access_delay, "Initial page access delay (microseconds)");
MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");
MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)");
MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)");
@@ -153,6 +158,7 @@ MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if
MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. "
"The size is specified in erase blocks and as the exponent of a power of two"
" e.g. 5 means a size of 32 erase blocks");
+MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory");
/* The largest possible page size */
#define NS_LARGEST_PAGE_SIZE 2048
@@ -266,6 +272,9 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I
*/
#define NS_MAX_PREVSTATES 1
+/* Maximum page cache pages needed to read or write a NAND page to the cache_file */
+#define NS_MAX_HELD_PAGES 16
+
/*
* A union to represent flash memory contents and flash buffer.
*/
@@ -295,6 +304,9 @@ struct nandsim {
/* The simulated NAND flash pages array */
union ns_mem *pages;
+ /* Slab allocator for nand pages */
+ struct kmem_cache *nand_pages_slab;
+
/* Internal buffer of page + OOB size bytes */
union ns_mem buf;
@@ -335,6 +347,13 @@ struct nandsim {
int ale; /* address Latch Enable */
int wp; /* write Protect */
} lines;
+
+ /* Fields needed when using a cache file */
+ struct file *cfile; /* Open file */
+ unsigned char *pages_written; /* Which pages have been written */
+ void *file_buf;
+ struct page *held_pages[NS_MAX_HELD_PAGES];
+ int held_cnt;
};
/*
@@ -420,25 +439,69 @@ static struct mtd_info *nsmtd;
static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE];
/*
- * Allocate array of page pointers and initialize the array to NULL
- * pointers.
+ * Allocate array of page pointers, create slab allocation for an array
+ * and initialize the array by NULL pointers.
*
* RETURNS: 0 if success, -ENOMEM if memory alloc fails.
*/
static int alloc_device(struct nandsim *ns)
{
- int i;
+ struct file *cfile;
+ int i, err;
+
+ if (cache_file) {
+ cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
+ if (IS_ERR(cfile))
+ return PTR_ERR(cfile);
+ if (!cfile->f_op || (!cfile->f_op->read && !cfile->f_op->aio_read)) {
+ NS_ERR("alloc_device: cache file not readable\n");
+ err = -EINVAL;
+ goto err_close;
+ }
+ if (!cfile->f_op->write && !cfile->f_op->aio_write) {
+ NS_ERR("alloc_device: cache file not writeable\n");
+ err = -EINVAL;
+ goto err_close;
+ }
+ ns->pages_written = vmalloc(ns->geom.pgnum);
+ if (!ns->pages_written) {
+ NS_ERR("alloc_device: unable to allocate pages written array\n");
+ err = -ENOMEM;
+ goto err_close;
+ }
+ ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
+ if (!ns->file_buf) {
+ NS_ERR("alloc_device: unable to allocate file buf\n");
+ err = -ENOMEM;
+ goto err_free;
+ }
+ ns->cfile = cfile;
+ memset(ns->pages_written, 0, ns->geom.pgnum);
+ return 0;
+ }
ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
if (!ns->pages) {
- NS_ERR("alloc_map: unable to allocate page array\n");
+ NS_ERR("alloc_device: unable to allocate page array\n");
return -ENOMEM;
}
for (i = 0; i < ns->geom.pgnum; i++) {
ns->pages[i].byte = NULL;
}
+ ns->nand_pages_slab = kmem_cache_create("nandsim",
+ ns->geom.pgszoob, 0, 0, NULL);
+ if (!ns->nand_pages_slab) {
+ NS_ERR("cache_create: unable to create kmem_cache\n");
+ return -ENOMEM;
+ }
return 0;
+
+err_free:
+ vfree(ns->pages_written);
+err_close:
+ filp_close(cfile, NULL);
+ return err;
}
/*
@@ -448,11 +511,20 @@ static void free_device(struct nandsim *ns)
{
int i;
+ if (ns->cfile) {
+ kfree(ns->file_buf);
+ vfree(ns->pages_written);
+ filp_close(ns->cfile, NULL);
+ return;
+ }
+
if (ns->pages) {
for (i = 0; i < ns->geom.pgnum; i++) {
if (ns->pages[i].byte)
- kfree(ns->pages[i].byte);
+ kmem_cache_free(ns->nand_pages_slab,
+ ns->pages[i].byte);
}
+ kmem_cache_destroy(ns->nand_pages_slab);
vfree(ns->pages);
}
}
@@ -464,7 +536,7 @@ static char *get_partition_name(int i)
return kstrdup(buf, GFP_KERNEL);
}
-static u_int64_t divide(u_int64_t n, u_int32_t d)
+static uint64_t divide(uint64_t n, uint32_t d)
{
do_div(n, d);
return n;
@@ -480,8 +552,8 @@ static int init_nandsim(struct mtd_info *mtd)
struct nand_chip *chip = (struct nand_chip *)mtd->priv;
struct nandsim *ns = (struct nandsim *)(chip->priv);
int i, ret = 0;
- u_int64_t remains;
- u_int64_t next_offset;
+ uint64_t remains;
+ uint64_t next_offset;
if (NS_IS_INITIALIZED(ns)) {
NS_ERR("init_nandsim: nandsim is already initialized\n");
@@ -548,7 +620,7 @@ static int init_nandsim(struct mtd_info *mtd)
remains = ns->geom.totsz;
next_offset = 0;
for (i = 0; i < parts_num; ++i) {
- u_int64_t part_sz = (u_int64_t)parts[i] * ns->geom.secsz;
+ uint64_t part_sz = (uint64_t)parts[i] * ns->geom.secsz;
if (!part_sz || part_sz > remains) {
NS_ERR("bad partition size.\n");
@@ -1211,6 +1283,97 @@ static int find_operation(struct nandsim *ns, uint32_t flag)
return -1;
}
+static void put_pages(struct nandsim *ns)
+{
+ int i;
+
+ for (i = 0; i < ns->held_cnt; i++)
+ page_cache_release(ns->held_pages[i]);
+}
+
+/* Get page cache pages in advance to provide NOFS memory allocation */
+static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos)
+{
+ pgoff_t index, start_index, end_index;
+ struct page *page;
+ struct address_space *mapping = file->f_mapping;
+
+ start_index = pos >> PAGE_CACHE_SHIFT;
+ end_index = (pos + count - 1) >> PAGE_CACHE_SHIFT;
+ if (end_index - start_index + 1 > NS_MAX_HELD_PAGES)
+ return -EINVAL;
+ ns->held_cnt = 0;
+ for (index = start_index; index <= end_index; index++) {
+ page = find_get_page(mapping, index);
+ if (page == NULL) {
+ page = find_or_create_page(mapping, index, GFP_NOFS);
+ if (page == NULL) {
+ write_inode_now(mapping->host, 1);
+ page = find_or_create_page(mapping, index, GFP_NOFS);
+ }
+ if (page == NULL) {
+ put_pages(ns);
+ return -ENOMEM;
+ }
+ unlock_page(page);
+ }
+ ns->held_pages[ns->held_cnt++] = page;
+ }
+ return 0;
+}
+
+static int set_memalloc(void)
+{
+ if (current->flags & PF_MEMALLOC)
+ return 0;
+ current->flags |= PF_MEMALLOC;
+ return 1;
+}
+
+static void clear_memalloc(int memalloc)
+{
+ if (memalloc)
+ current->flags &= ~PF_MEMALLOC;
+}
+
+static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos)
+{
+ mm_segment_t old_fs;
+ ssize_t tx;
+ int err, memalloc;
+
+ err = get_pages(ns, file, count, *pos);
+ if (err)
+ return err;
+ old_fs = get_fs();
+ set_fs(get_ds());
+ memalloc = set_memalloc();
+ tx = vfs_read(file, (char __user *)buf, count, pos);
+ clear_memalloc(memalloc);
+ set_fs(old_fs);
+ put_pages(ns);
+ return tx;
+}
+
+static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos)
+{
+ mm_segment_t old_fs;
+ ssize_t tx;
+ int err, memalloc;
+
+ err = get_pages(ns, file, count, *pos);
+ if (err)
+ return err;
+ old_fs = get_fs();
+ set_fs(get_ds());
+ memalloc = set_memalloc();
+ tx = vfs_write(file, (char __user *)buf, count, pos);
+ clear_memalloc(memalloc);
+ set_fs(old_fs);
+ put_pages(ns);
+ return tx;
+}
+
/*
* Returns a pointer to the current page.
*/
@@ -1227,6 +1390,38 @@ static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
}
+int do_read_error(struct nandsim *ns, int num)
+{
+ unsigned int page_no = ns->regs.row;
+
+ if (read_error(page_no)) {
+ int i;
+ memset(ns->buf.byte, 0xFF, num);
+ for (i = 0; i < num; ++i)
+ ns->buf.byte[i] = random32();
+ NS_WARN("simulating read error in page %u\n", page_no);
+ return 1;
+ }
+ return 0;
+}
+
+void do_bit_flips(struct nandsim *ns, int num)
+{
+ if (bitflips && random32() < (1 << 22)) {
+ int flips = 1;
+ if (bitflips > 1)
+ flips = (random32() % (int) bitflips) + 1;
+ while (flips--) {
+ int pos = random32() % (num * 8);
+ ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
+ NS_WARN("read_page: flipping bit %d in page %d "
+ "reading from %d ecc: corrected=%u failed=%u\n",
+ pos, ns->regs.row, ns->regs.column + ns->regs.off,
+ nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
+ }
+ }
+}
+
/*
* Fill the NAND buffer with data read from the specified page.
*/
@@ -1234,36 +1429,40 @@ static void read_page(struct nandsim *ns, int num)
{
union ns_mem *mypage;
+ if (ns->cfile) {
+ if (!ns->pages_written[ns->regs.row]) {
+ NS_DBG("read_page: page %d not written\n", ns->regs.row);
+ memset(ns->buf.byte, 0xFF, num);
+ } else {
+ loff_t pos;
+ ssize_t tx;
+
+ NS_DBG("read_page: page %d written, reading from %d\n",
+ ns->regs.row, ns->regs.column + ns->regs.off);
+ if (do_read_error(ns, num))
+ return;
+ pos = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off;
+ tx = read_file(ns, ns->cfile, ns->buf.byte, num, &pos);
+ if (tx != num) {
+ NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
+ return;
+ }
+ do_bit_flips(ns, num);
+ }
+ return;
+ }
+
mypage = NS_GET_PAGE(ns);
if (mypage->byte == NULL) {
NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
memset(ns->buf.byte, 0xFF, num);
} else {
- unsigned int page_no = ns->regs.row;
NS_DBG("read_page: page %d allocated, reading from %d\n",
ns->regs.row, ns->regs.column + ns->regs.off);
- if (read_error(page_no)) {
- int i;
- memset(ns->buf.byte, 0xFF, num);
- for (i = 0; i < num; ++i)
- ns->buf.byte[i] = random32();
- NS_WARN("simulating read error in page %u\n", page_no);
+ if (do_read_error(ns, num))
return;
- }
memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
- if (bitflips && random32() < (1 << 22)) {
- int flips = 1;
- if (bitflips > 1)
- flips = (random32() % (int) bitflips) + 1;
- while (flips--) {
- int pos = random32() % (num * 8);
- ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
- NS_WARN("read_page: flipping bit %d in page %d "
- "reading from %d ecc: corrected=%u failed=%u\n",
- pos, ns->regs.row, ns->regs.column + ns->regs.off,
- nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
- }
- }
+ do_bit_flips(ns, num);
}
}
@@ -1275,11 +1474,20 @@ static void erase_sector(struct nandsim *ns)
union ns_mem *mypage;
int i;
+ if (ns->cfile) {
+ for (i = 0; i < ns->geom.pgsec; i++)
+ if (ns->pages_written[ns->regs.row + i]) {
+ NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
+ ns->pages_written[ns->regs.row + i] = 0;
+ }
+ return;
+ }
+
mypage = NS_GET_PAGE(ns);
for (i = 0; i < ns->geom.pgsec; i++) {
if (mypage->byte != NULL) {
NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
- kfree(mypage->byte);
+ kmem_cache_free(ns->nand_pages_slab, mypage->byte);
mypage->byte = NULL;
}
mypage++;
@@ -1295,16 +1503,57 @@ static int prog_page(struct nandsim *ns, int num)
union ns_mem *mypage;
u_char *pg_off;
+ if (ns->cfile) {
+ loff_t off, pos;
+ ssize_t tx;
+ int all;
+
+ NS_DBG("prog_page: writing page %d\n", ns->regs.row);
+ pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
+ off = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off;
+ if (!ns->pages_written[ns->regs.row]) {
+ all = 1;
+ memset(ns->file_buf, 0xff, ns->geom.pgszoob);
+ } else {
+ all = 0;
+ pos = off;
+ tx = read_file(ns, ns->cfile, pg_off, num, &pos);
+ if (tx != num) {
+ NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
+ return -1;
+ }
+ }
+ for (i = 0; i < num; i++)
+ pg_off[i] &= ns->buf.byte[i];
+ if (all) {
+ pos = (loff_t)ns->regs.row * ns->geom.pgszoob;
+ tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, &pos);
+ if (tx != ns->geom.pgszoob) {
+ NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+ return -1;
+ }
+ ns->pages_written[ns->regs.row] = 1;
+ } else {
+ pos = off;
+ tx = write_file(ns, ns->cfile, pg_off, num, &pos);
+ if (tx != num) {
+ NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
+ return -1;
+ }
+ }
+ return 0;
+ }
+
mypage = NS_GET_PAGE(ns);
if (mypage->byte == NULL) {
NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
/*
* We allocate memory with GFP_NOFS because a flash FS may
* utilize this. If it is holding an FS lock, then gets here,
- * then kmalloc runs writeback which goes to the FS again
- * and deadlocks. This was seen in practice.
+ * then kernel memory alloc runs writeback which goes to the FS
+ * again and deadlocks. This was seen in practice.
*/
- mypage->byte = kmalloc(ns->geom.pgszoob, GFP_NOFS);
+ mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS);
if (mypage->byte == NULL) {
NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
return -1;
@@ -1736,13 +1985,17 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
/* Check if chip is expecting command */
if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) {
- /*
- * We are in situation when something else (not command)
- * was expected but command was input. In this case ignore
- * previous command(s)/state(s) and accept the last one.
- */
- NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, "
- "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
+ /* Do not warn if only 2 id bytes are read */
+ if (!(ns->regs.command == NAND_CMD_READID &&
+ NS_STATE(ns->state) == STATE_DATAOUT_ID && ns->regs.count == 2)) {
+ /*
+ * We are in situation when something else (not command)
+ * was expected but command was input. In this case ignore
+ * previous command(s)/state(s) and accept the last one.
+ */
+ NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, "
+ "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
+ }
switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
}
@@ -2044,7 +2297,7 @@ static int __init ns_init_module(void)
}
if (overridesize) {
- u_int64_t new_size = (u_int64_t)nsmtd->erasesize << overridesize;
+ uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize;
if (new_size >> overridesize != nsmtd->erasesize) {
NS_ERR("overridesize is too big\n");
goto err_exit;
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 955959eb02d4..582cf80f555a 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -2,12 +2,20 @@
* drivers/mtd/ndfc.c
*
* Overview:
- * Platform independend driver for NDFC (NanD Flash Controller)
+ * Platform independent driver for NDFC (NanD Flash Controller)
* integrated into EP440 cores
*
+ * Ported to an OF platform driver by Sean MacLennan
+ *
+ * The NDFC supports multiple chips, but this driver only supports a
+ * single chip since I do not have access to any boards with
+ * multiple chips.
+ *
* Author: Thomas Gleixner
*
* Copyright 2006 IBM
+ * Copyright 2008 PIKA Technologies
+ * Sean MacLennan <smaclennan@pikatech.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
@@ -21,27 +29,20 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/ndfc.h>
#include <linux/mtd/mtd.h>
-#include <linux/platform_device.h>
-
+#include <linux/of_platform.h>
#include <asm/io.h>
-#ifdef CONFIG_40x
-#include <asm/ibm405.h>
-#else
-#include <asm/ibm44x.h>
-#endif
-
-struct ndfc_nand_mtd {
- struct mtd_info mtd;
- struct nand_chip chip;
- struct platform_nand_chip *pl_chip;
-};
-static struct ndfc_nand_mtd ndfc_mtd[NDFC_MAX_BANKS];
struct ndfc_controller {
- void __iomem *ndfcbase;
- struct nand_hw_control ndfc_control;
- atomic_t childs_active;
+ struct of_device *ofdev;
+ void __iomem *ndfcbase;
+ struct mtd_info mtd;
+ struct nand_chip chip;
+ int chip_select;
+ struct nand_hw_control ndfc_control;
+#ifdef CONFIG_MTD_PARTITIONS
+ struct mtd_partition *parts;
+#endif
};
static struct ndfc_controller ndfc_ctrl;
@@ -50,17 +51,14 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
{
uint32_t ccr;
struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct nand_chip *nandchip = mtd->priv;
- struct ndfc_nand_mtd *nandmtd = nandchip->priv;
- struct platform_nand_chip *pchip = nandmtd->pl_chip;
- ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
+ ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
if (chip >= 0) {
ccr &= ~NDFC_CCR_BS_MASK;
- ccr |= NDFC_CCR_BS(chip + pchip->chip_offset);
+ ccr |= NDFC_CCR_BS(chip + ndfc->chip_select);
} else
ccr |= NDFC_CCR_RESET_CE;
- __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
+ out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
}
static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
@@ -80,7 +78,7 @@ static int ndfc_ready(struct mtd_info *mtd)
{
struct ndfc_controller *ndfc = &ndfc_ctrl;
- return __raw_readl(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
+ return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
}
static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
@@ -88,9 +86,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
uint32_t ccr;
struct ndfc_controller *ndfc = &ndfc_ctrl;
- ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR);
+ ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
ccr |= NDFC_CCR_RESET_ECC;
- __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
+ out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
wmb();
}
@@ -102,9 +100,10 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
uint8_t *p = (uint8_t *)&ecc;
wmb();
- ecc = __raw_readl(ndfc->ndfcbase + NDFC_ECC);
- ecc_code[0] = p[1];
- ecc_code[1] = p[2];
+ ecc = in_be32(ndfc->ndfcbase + NDFC_ECC);
+ /* The NDFC uses Smart Media (SMC) bytes order */
+ ecc_code[0] = p[2];
+ ecc_code[1] = p[1];
ecc_code[2] = p[3];
return 0;
@@ -123,7 +122,7 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- *p++ = __raw_readl(ndfc->ndfcbase + NDFC_DATA);
+ *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
}
static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
@@ -132,7 +131,7 @@ static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- __raw_writel(*p++, ndfc->ndfcbase + NDFC_DATA);
+ out_be32(ndfc->ndfcbase + NDFC_DATA, *p++);
}
static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
@@ -141,7 +140,7 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
uint32_t *p = (uint32_t *) buf;
for(;len > 0; len -= 4)
- if (*p++ != __raw_readl(ndfc->ndfcbase + NDFC_DATA))
+ if (*p++ != in_be32(ndfc->ndfcbase + NDFC_DATA))
return -EFAULT;
return 0;
}
@@ -149,10 +148,19 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
/*
* Initialize chip structure
*/
-static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
+static int ndfc_chip_init(struct ndfc_controller *ndfc,
+ struct device_node *node)
{
- struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct nand_chip *chip = &mtd->chip;
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ static const char *part_types[] = { "cmdlinepart", NULL };
+#else
+ static const char *part_types[] = { NULL };
+#endif
+#endif
+ struct device_node *flash_np;
+ struct nand_chip *chip = &ndfc->chip;
+ int ret;
chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
@@ -160,8 +168,6 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->dev_ready = ndfc_ready;
chip->select_chip = ndfc_select_chip;
chip->chip_delay = 50;
- chip->priv = mtd;
- chip->options = mtd->pl_chip->options;
chip->controller = &ndfc->ndfc_control;
chip->read_buf = ndfc_read_buf;
chip->write_buf = ndfc_write_buf;
@@ -172,143 +178,136 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 256;
chip->ecc.bytes = 3;
- chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout;
- mtd->mtd.priv = chip;
- mtd->mtd.owner = THIS_MODULE;
-}
-
-static int ndfc_chip_probe(struct platform_device *pdev)
-{
- struct platform_nand_chip *nc = pdev->dev.platform_data;
- struct ndfc_chip_settings *settings = nc->priv;
- struct ndfc_controller *ndfc = &ndfc_ctrl;
- struct ndfc_nand_mtd *nandmtd;
-
- if (nc->chip_offset >= NDFC_MAX_BANKS || nc->nr_chips > NDFC_MAX_BANKS)
- return -EINVAL;
-
- /* Set the bank settings */
- __raw_writel(settings->bank_settings,
- ndfc->ndfcbase + NDFC_BCFG0 + (nc->chip_offset << 2));
- nandmtd = &ndfc_mtd[pdev->id];
- if (nandmtd->pl_chip)
- return -EBUSY;
+ ndfc->mtd.priv = chip;
+ ndfc->mtd.owner = THIS_MODULE;
- nandmtd->pl_chip = nc;
- ndfc_chip_init(nandmtd);
-
- /* Scan for chips */
- if (nand_scan(&nandmtd->mtd, nc->nr_chips)) {
- nandmtd->pl_chip = NULL;
+ flash_np = of_get_next_child(node, NULL);
+ if (!flash_np)
return -ENODEV;
+
+ ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s",
+ ndfc->ofdev->dev.bus_id, flash_np->name);
+ if (!ndfc->mtd.name) {
+ ret = -ENOMEM;
+ goto err;
}
-#ifdef CONFIG_MTD_PARTITIONS
- printk("Number of partitions %d\n", nc->nr_partitions);
- if (nc->nr_partitions) {
- /* Add the full device, so complete dumps can be made */
- add_mtd_device(&nandmtd->mtd);
- add_mtd_partitions(&nandmtd->mtd, nc->partitions,
- nc->nr_partitions);
+ ret = nand_scan(&ndfc->mtd, 1);
+ if (ret)
+ goto err;
- } else
-#else
- add_mtd_device(&nandmtd->mtd);
+#ifdef CONFIG_MTD_PARTITIONS
+ ret = parse_mtd_partitions(&ndfc->mtd, part_types, &ndfc->parts, 0);
+ if (ret < 0)
+ goto err;
+
+#ifdef CONFIG_MTD_OF_PARTS
+ if (ret == 0) {
+ ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, flash_np,
+ &ndfc->parts);
+ if (ret < 0)
+ goto err;
+ }
#endif
- atomic_inc(&ndfc->childs_active);
- return 0;
-}
+ if (ret > 0)
+ ret = add_mtd_partitions(&ndfc->mtd, ndfc->parts, ret);
+ else
+#endif
+ ret = add_mtd_device(&ndfc->mtd);
-static int ndfc_chip_remove(struct platform_device *pdev)
-{
- return 0;
+err:
+ of_node_put(flash_np);
+ if (ret)
+ kfree(ndfc->mtd.name);
+ return ret;
}
-static int ndfc_nand_probe(struct platform_device *pdev)
+static int __devinit ndfc_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
{
- struct platform_nand_ctrl *nc = pdev->dev.platform_data;
- struct ndfc_controller_settings *settings = nc->priv;
- struct resource *res = pdev->resource;
struct ndfc_controller *ndfc = &ndfc_ctrl;
- unsigned long long phys = settings->ndfc_erpn | res->start;
+ const u32 *reg;
+ u32 ccr;
+ int err, len;
-#ifndef CONFIG_PHYS_64BIT
- ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1);
-#else
- ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1);
-#endif
+ spin_lock_init(&ndfc->ndfc_control.lock);
+ init_waitqueue_head(&ndfc->ndfc_control.wq);
+ ndfc->ofdev = ofdev;
+ dev_set_drvdata(&ofdev->dev, ndfc);
+
+ /* Read the reg property to get the chip select */
+ reg = of_get_property(ofdev->node, "reg", &len);
+ if (reg == NULL || len != 12) {
+ dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
+ return -ENOENT;
+ }
+ ndfc->chip_select = reg[0];
+
+ ndfc->ndfcbase = of_iomap(ofdev->node, 0);
if (!ndfc->ndfcbase) {
- printk(KERN_ERR "NDFC: ioremap failed\n");
+ dev_err(&ofdev->dev, "failed to get memory\n");
return -EIO;
}
- __raw_writel(settings->ccr_settings, ndfc->ndfcbase + NDFC_CCR);
+ ccr = NDFC_CCR_BS(ndfc->chip_select);
- spin_lock_init(&ndfc->ndfc_control.lock);
- init_waitqueue_head(&ndfc->ndfc_control.wq);
+ /* It is ok if ccr does not exist - just default to 0 */
+ reg = of_get_property(ofdev->node, "ccr", NULL);
+ if (reg)
+ ccr |= *reg;
- platform_set_drvdata(pdev, ndfc);
+ out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
- printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n",
- __raw_readl(ndfc->ndfcbase + NDFC_REVID));
+ /* Set the bank settings if given */
+ reg = of_get_property(ofdev->node, "bank-settings", NULL);
+ if (reg) {
+ int offset = NDFC_BCFG0 + (ndfc->chip_select << 2);
+ out_be32(ndfc->ndfcbase + offset, *reg);
+ }
+
+ err = ndfc_chip_init(ndfc, ofdev->node);
+ if (err) {
+ iounmap(ndfc->ndfcbase);
+ return err;
+ }
return 0;
}
-static int ndfc_nand_remove(struct platform_device *pdev)
+static int __devexit ndfc_remove(struct of_device *ofdev)
{
- struct ndfc_controller *ndfc = platform_get_drvdata(pdev);
+ struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
- if (atomic_read(&ndfc->childs_active))
- return -EBUSY;
+ nand_release(&ndfc->mtd);
- if (ndfc) {
- platform_set_drvdata(pdev, NULL);
- iounmap(ndfc_ctrl.ndfcbase);
- ndfc_ctrl.ndfcbase = NULL;
- }
return 0;
}
-/* driver device registration */
-
-static struct platform_driver ndfc_chip_driver = {
- .probe = ndfc_chip_probe,
- .remove = ndfc_chip_remove,
- .driver = {
- .name = "ndfc-chip",
- .owner = THIS_MODULE,
- },
+static const struct of_device_id ndfc_match[] = {
+ { .compatible = "ibm,ndfc", },
+ {}
};
+MODULE_DEVICE_TABLE(of, ndfc_match);
-static struct platform_driver ndfc_nand_driver = {
- .probe = ndfc_nand_probe,
- .remove = ndfc_nand_remove,
- .driver = {
- .name = "ndfc-nand",
- .owner = THIS_MODULE,
+static struct of_platform_driver ndfc_driver = {
+ .driver = {
+ .name = "ndfc",
},
+ .match_table = ndfc_match,
+ .probe = ndfc_probe,
+ .remove = __devexit_p(ndfc_remove),
};
static int __init ndfc_nand_init(void)
{
- int ret;
-
- spin_lock_init(&ndfc_ctrl.ndfc_control.lock);
- init_waitqueue_head(&ndfc_ctrl.ndfc_control.wq);
-
- ret = platform_driver_register(&ndfc_nand_driver);
- if (!ret)
- ret = platform_driver_register(&ndfc_chip_driver);
- return ret;
+ return of_register_platform_driver(&ndfc_driver);
}
static void __exit ndfc_nand_exit(void)
{
- platform_driver_unregister(&ndfc_chip_driver);
- platform_driver_unregister(&ndfc_nand_driver);
+ of_unregister_platform_driver(&ndfc_driver);
}
module_init(ndfc_nand_init);
@@ -316,6 +315,4 @@ module_exit(ndfc_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
-MODULE_DESCRIPTION("Platform driver for NDFC");
-MODULE_ALIAS("platform:ndfc-chip");
-MODULE_ALIAS("platform:ndfc-nand");
+MODULE_DESCRIPTION("OF Platform driver for NDFC");
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index fc4144495610..cc55cbc2b308 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -298,7 +298,7 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = {
#define NDTR1_tAR(c) (min((c), 15) << 0)
/* convert nano-seconds to nand flash controller clock cycles */
-#define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) + 1)
+#define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) - 1)
static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
const struct pxa3xx_nand_timing *t)
@@ -368,14 +368,14 @@ static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
/* large block, 2 cycles for column address
* row address starts from 3rd cycle
*/
- info->ndcb1 |= (page_addr << 16) | (column & 0xffff);
+ info->ndcb1 |= page_addr << 16;
if (info->row_addr_cycles == 3)
info->ndcb2 = (page_addr >> 16) & 0xff;
} else
/* small block, 1 cycles for column address
* row address starts from 2nd cycle
*/
- info->ndcb1 = (page_addr << 8) | (column & 0xff);
+ info->ndcb1 = page_addr << 8;
if (cmd == cmdset->program)
info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index 30a518e211bd..54ec7542a7b7 100644
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -2,6 +2,7 @@
* drivers/mtd/nand/sharpsl.c
*
* Copyright (C) 2004 Richard Purdie
+ * Copyright (C) 2008 Dmitry Baryshkov
*
* Based on Sharp's NAND driver sharp_sl.c
*
@@ -19,22 +20,31 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/sharpsl.h>
#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
#include <asm/io.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
-static void __iomem *sharpsl_io_base;
-static int sharpsl_phys_base = 0x0C000000;
+struct sharpsl_nand {
+ struct mtd_info mtd;
+ struct nand_chip chip;
+
+ void __iomem *io;
+};
+
+#define mtd_to_sharpsl(_mtd) container_of(_mtd, struct sharpsl_nand, mtd)
/* register offset */
-#define ECCLPLB sharpsl_io_base+0x00 /* line parity 7 - 0 bit */
-#define ECCLPUB sharpsl_io_base+0x04 /* line parity 15 - 8 bit */
-#define ECCCP sharpsl_io_base+0x08 /* column parity 5 - 0 bit */
-#define ECCCNTR sharpsl_io_base+0x0C /* ECC byte counter */
-#define ECCCLRR sharpsl_io_base+0x10 /* cleare ECC */
-#define FLASHIO sharpsl_io_base+0x14 /* Flash I/O */
-#define FLASHCTL sharpsl_io_base+0x18 /* Flash Control */
+#define ECCLPLB 0x00 /* line parity 7 - 0 bit */
+#define ECCLPUB 0x04 /* line parity 15 - 8 bit */
+#define ECCCP 0x08 /* column parity 5 - 0 bit */
+#define ECCCNTR 0x0C /* ECC byte counter */
+#define ECCCLRR 0x10 /* cleare ECC */
+#define FLASHIO 0x14 /* Flash I/O */
+#define FLASHCTL 0x18 /* Flash Control */
/* Flash control bit */
#define FLRYBY (1 << 5)
@@ -45,35 +55,6 @@ static int sharpsl_phys_base = 0x0C000000;
#define FLCE0 (1 << 0)
/*
- * MTD structure for SharpSL
- */
-static struct mtd_info *sharpsl_mtd = NULL;
-
-/*
- * Define partitions for flash device
- */
-#define DEFAULT_NUM_PARTITIONS 3
-
-static int nr_partitions;
-static struct mtd_partition sharpsl_nand_default_partition_info[] = {
- {
- .name = "System Area",
- .offset = 0,
- .size = 7 * 1024 * 1024,
- },
- {
- .name = "Root Filesystem",
- .offset = 7 * 1024 * 1024,
- .size = 30 * 1024 * 1024,
- },
- {
- .name = "Home Filesystem",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-/*
* hardware specific access to control-lines
* ctrl:
* NAND_CNE: bit 0 -> ! bit 0 & 4
@@ -84,6 +65,7 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = {
static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
+ struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
struct nand_chip *chip = mtd->priv;
if (ctrl & NAND_CTRL_CHANGE) {
@@ -93,103 +75,97 @@ static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
bits ^= 0x11;
- writeb((readb(FLASHCTL) & ~0x17) | bits, FLASHCTL);
+ writeb((readb(sharpsl->io + FLASHCTL) & ~0x17) | bits, sharpsl->io + FLASHCTL);
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
}
-static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
-
-static struct nand_bbt_descr sharpsl_bbt = {
- .options = 0,
- .offs = 4,
- .len = 2,
- .pattern = scan_ff_pattern
-};
-
-static struct nand_bbt_descr sharpsl_akita_bbt = {
- .options = 0,
- .offs = 4,
- .len = 1,
- .pattern = scan_ff_pattern
-};
-
-static struct nand_ecclayout akita_oobinfo = {
- .eccbytes = 24,
- .eccpos = {
- 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11,
- 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
- 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37},
- .oobfree = {{0x08, 0x09}}
-};
-
static int sharpsl_nand_dev_ready(struct mtd_info *mtd)
{
- return !((readb(FLASHCTL) & FLRYBY) == 0);
+ struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+ return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0);
}
static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
- writeb(0, ECCCLRR);
+ struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+ writeb(0, sharpsl->io + ECCCLRR);
}
static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code)
{
- ecc_code[0] = ~readb(ECCLPUB);
- ecc_code[1] = ~readb(ECCLPLB);
- ecc_code[2] = (~readb(ECCCP) << 2) | 0x03;
- return readb(ECCCNTR) != 0;
+ struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
+ ecc_code[0] = ~readb(sharpsl->io + ECCLPUB);
+ ecc_code[1] = ~readb(sharpsl->io + ECCLPLB);
+ ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03;
+ return readb(sharpsl->io + ECCCNTR) != 0;
}
#ifdef CONFIG_MTD_PARTITIONS
-const char *part_probes[] = { "cmdlinepart", NULL };
+static const char *part_probes[] = { "cmdlinepart", NULL };
#endif
/*
* Main initialization routine
*/
-static int __init sharpsl_nand_init(void)
+static int __devinit sharpsl_nand_probe(struct platform_device *pdev)
{
struct nand_chip *this;
+#ifdef CONFIG_MTD_PARTITIONS
struct mtd_partition *sharpsl_partition_info;
+ int nr_partitions;
+#endif
+ struct resource *r;
int err = 0;
+ struct sharpsl_nand *sharpsl;
+ struct sharpsl_nand_platform_data *data = pdev->dev.platform_data;
+
+ if (!data) {
+ dev_err(&pdev->dev, "no platform data!\n");
+ return -EINVAL;
+ }
/* Allocate memory for MTD device structure and private data */
- sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
- if (!sharpsl_mtd) {
+ sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL);
+ if (!sharpsl) {
printk("Unable to allocate SharpSL NAND MTD device structure.\n");
return -ENOMEM;
}
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "no io memory resource defined!\n");
+ err = -ENODEV;
+ goto err_get_res;
+ }
+
/* map physical address */
- sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000);
- if (!sharpsl_io_base) {
+ sharpsl->io = ioremap(r->start, resource_size(r));
+ if (!sharpsl->io) {
printk("ioremap to access Sharp SL NAND chip failed\n");
- kfree(sharpsl_mtd);
- return -EIO;
+ err = -EIO;
+ goto err_ioremap;
}
/* Get pointer to private data */
- this = (struct nand_chip *)(&sharpsl_mtd[1]);
-
- /* Initialize structures */
- memset(sharpsl_mtd, 0, sizeof(struct mtd_info));
- memset(this, 0, sizeof(struct nand_chip));
+ this = (struct nand_chip *)(&sharpsl->chip);
/* Link the private data with the MTD structure */
- sharpsl_mtd->priv = this;
- sharpsl_mtd->owner = THIS_MODULE;
+ sharpsl->mtd.priv = this;
+ sharpsl->mtd.owner = THIS_MODULE;
+
+ platform_set_drvdata(pdev, sharpsl);
/*
* PXA initialize
*/
- writeb(readb(FLASHCTL) | FLWP, FLASHCTL);
+ writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL);
/* Set address of NAND IO lines */
- this->IO_ADDR_R = FLASHIO;
- this->IO_ADDR_W = FLASHIO;
+ this->IO_ADDR_R = sharpsl->io + FLASHIO;
+ this->IO_ADDR_W = sharpsl->io + FLASHIO;
/* Set address of hardware control function */
this->cmd_ctrl = sharpsl_nand_hwcontrol;
this->dev_ready = sharpsl_nand_dev_ready;
@@ -199,68 +175,89 @@ static int __init sharpsl_nand_init(void)
this->ecc.mode = NAND_ECC_HW;
this->ecc.size = 256;
this->ecc.bytes = 3;
- this->badblock_pattern = &sharpsl_bbt;
- if (machine_is_akita() || machine_is_borzoi()) {
- this->badblock_pattern = &sharpsl_akita_bbt;
- this->ecc.layout = &akita_oobinfo;
- }
+ this->badblock_pattern = data->badblock_pattern;
+ this->ecc.layout = data->ecc_layout;
this->ecc.hwctl = sharpsl_nand_enable_hwecc;
this->ecc.calculate = sharpsl_nand_calculate_ecc;
this->ecc.correct = nand_correct_data;
/* Scan to find existence of the device */
- err = nand_scan(sharpsl_mtd, 1);
- if (err) {
- iounmap(sharpsl_io_base);
- kfree(sharpsl_mtd);
- return err;
- }
+ err = nand_scan(&sharpsl->mtd, 1);
+ if (err)
+ goto err_scan;
/* Register the partitions */
- sharpsl_mtd->name = "sharpsl-nand";
- nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, &sharpsl_partition_info, 0);
-
+ sharpsl->mtd.name = "sharpsl-nand";
+#ifdef CONFIG_MTD_PARTITIONS
+ nr_partitions = parse_mtd_partitions(&sharpsl->mtd, part_probes, &sharpsl_partition_info, 0);
if (nr_partitions <= 0) {
- nr_partitions = DEFAULT_NUM_PARTITIONS;
- sharpsl_partition_info = sharpsl_nand_default_partition_info;
- if (machine_is_poodle()) {
- sharpsl_partition_info[1].size = 22 * 1024 * 1024;
- } else if (machine_is_corgi() || machine_is_shepherd()) {
- sharpsl_partition_info[1].size = 25 * 1024 * 1024;
- } else if (machine_is_husky()) {
- sharpsl_partition_info[1].size = 53 * 1024 * 1024;
- } else if (machine_is_spitz()) {
- sharpsl_partition_info[1].size = 5 * 1024 * 1024;
- } else if (machine_is_akita()) {
- sharpsl_partition_info[1].size = 58 * 1024 * 1024;
- } else if (machine_is_borzoi()) {
- sharpsl_partition_info[1].size = 32 * 1024 * 1024;
- }
+ nr_partitions = data->nr_partitions;
+ sharpsl_partition_info = data->partitions;
}
- add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions);
+ if (nr_partitions > 0)
+ err = add_mtd_partitions(&sharpsl->mtd, sharpsl_partition_info, nr_partitions);
+ else
+#endif
+ err = add_mtd_device(&sharpsl->mtd);
+ if (err)
+ goto err_add;
/* Return happy */
return 0;
-}
-module_init(sharpsl_nand_init);
+err_add:
+ nand_release(&sharpsl->mtd);
+
+err_scan:
+ platform_set_drvdata(pdev, NULL);
+ iounmap(sharpsl->io);
+err_ioremap:
+err_get_res:
+ kfree(sharpsl);
+ return err;
+}
/*
* Clean up routine
*/
-static void __exit sharpsl_nand_cleanup(void)
+static int __devexit sharpsl_nand_remove(struct platform_device *pdev)
{
+ struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
+
/* Release resources, unregister device */
- nand_release(sharpsl_mtd);
+ nand_release(&sharpsl->mtd);
- iounmap(sharpsl_io_base);
+ platform_set_drvdata(pdev, NULL);
+
+ iounmap(sharpsl->io);
/* Free the MTD device structure */
- kfree(sharpsl_mtd);
+ kfree(sharpsl);
+
+ return 0;
+}
+
+static struct platform_driver sharpsl_nand_driver = {
+ .driver = {
+ .name = "sharpsl-nand",
+ .owner = THIS_MODULE,
+ },
+ .probe = sharpsl_nand_probe,
+ .remove = __devexit_p(sharpsl_nand_remove),
+};
+
+static int __init sharpsl_nand_init(void)
+{
+ return platform_driver_register(&sharpsl_nand_driver);
}
+module_init(sharpsl_nand_init);
-module_exit(sharpsl_nand_cleanup);
+static void __exit sharpsl_nand_exit(void)
+{
+ platform_driver_unregister(&sharpsl_nand_driver);
+}
+module_exit(sharpsl_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index 320b929abe79..d1c4546513f7 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -39,7 +39,7 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
struct NFTLrecord *nftl;
unsigned long temp;
- if (mtd->type != MTD_NANDFLASH)
+ if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX)
return;
/* OK, this is moderately ugly. But probably safe. Alternatives? */
if (memcmp(mtd->name, "DiskOnChip", 10))
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
index ccc4f209fbb5..8b22b1836e9f 100644
--- a/drivers/mtd/nftlmount.c
+++ b/drivers/mtd/nftlmount.c
@@ -51,7 +51,7 @@ static int find_boot_record(struct NFTLrecord *nftl)
the mtd device accordingly. We could even get rid of
nftl->EraseSize if there were any point in doing so. */
nftl->EraseSize = nftl->mbd.mtd->erasesize;
- nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
+ nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize;
nftl->MediaUnit = BLOCK_NIL;
nftl->SpareMediaUnit = BLOCK_NIL;
@@ -168,7 +168,7 @@ device is already correct.
printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n",
mh->UnitSizeFactor);
nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor);
- nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
+ nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize;
}
#endif
nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 90ed319f26e6..529af271db17 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1772,7 +1772,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
int len;
int ret = 0;
- DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
+ DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%012llx, len = %llu\n", (unsigned long long) instr->addr, (unsigned long long) instr->len);
block_size = (1 << this->erase_shift);
@@ -1810,7 +1810,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
/* Check if we have a bad block, we do not erase bad blocks */
if (onenand_block_isbad_nolock(mtd, addr, 0)) {
- printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr);
+ printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%012llx\n", (unsigned long long) addr);
instr->state = MTD_ERASE_FAILED;
goto erase_exit;
}
@@ -2029,7 +2029,7 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int
*
* Lock one or more blocks
*/
-static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int onenand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
int ret;
@@ -2047,7 +2047,7 @@ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
*
* Unlock one or more blocks
*/
-static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
int ret;
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index e538c0a72abb..d2aa9c46530f 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -21,8 +21,6 @@
#include <asm/types.h>
-#define const_cpu_to_le16 __constant_cpu_to_le16
-
static int block_size = 0;
module_param(block_size, int, 0);
MODULE_PARM_DESC(block_size, "Block size to use by RFD, defaults to erase unit size");
@@ -156,7 +154,7 @@ static int scan_header(struct partition *part)
size_t retlen;
sectors_per_block = part->block_size / SECTOR_SIZE;
- part->total_blocks = part->mbd.mtd->size / part->block_size;
+ part->total_blocks = (u32)part->mbd.mtd->size / part->block_size;
if (part->total_blocks < 2)
return -ENOENT;
@@ -276,16 +274,17 @@ static void erase_callback(struct erase_info *erase)
part = (struct partition*)erase->priv;
- i = erase->addr / part->block_size;
- if (i >= part->total_blocks || part->blocks[i].offset != erase->addr) {
- printk(KERN_ERR PREFIX "erase callback for unknown offset %x "
- "on '%s'\n", erase->addr, part->mbd.mtd->name);
+ i = (u32)erase->addr / part->block_size;
+ if (i >= part->total_blocks || part->blocks[i].offset != erase->addr ||
+ erase->addr > UINT_MAX) {
+ printk(KERN_ERR PREFIX "erase callback for unknown offset %llx "
+ "on '%s'\n", (unsigned long long)erase->addr, part->mbd.mtd->name);
return;
}
if (erase->state != MTD_ERASE_DONE) {
- printk(KERN_WARNING PREFIX "erase failed at 0x%x on '%s', "
- "state %d\n", erase->addr,
+ printk(KERN_WARNING PREFIX "erase failed at 0x%llx on '%s', "
+ "state %d\n", (unsigned long long)erase->addr,
part->mbd.mtd->name, erase->state);
part->blocks[i].state = BLOCK_FAILED;
@@ -297,7 +296,7 @@ static void erase_callback(struct erase_info *erase)
return;
}
- magic = const_cpu_to_le16(RFD_MAGIC);
+ magic = cpu_to_le16(RFD_MAGIC);
part->blocks[i].state = BLOCK_ERASED;
part->blocks[i].free_sectors = part->data_sectors_per_block;
@@ -345,9 +344,9 @@ static int erase_block(struct partition *part, int block)
rc = part->mbd.mtd->erase(part->mbd.mtd, erase);
if (rc) {
- printk(KERN_ERR PREFIX "erase of region %x,%x on '%s' "
- "failed\n", erase->addr, erase->len,
- part->mbd.mtd->name);
+ printk(KERN_ERR PREFIX "erase of region %llx,%llx on '%s' "
+ "failed\n", (unsigned long long)erase->addr,
+ (unsigned long long)erase->len, part->mbd.mtd->name);
kfree(erase);
}
@@ -587,7 +586,7 @@ static int mark_sector_deleted(struct partition *part, u_long old_addr)
int block, offset, rc;
u_long addr;
size_t retlen;
- u16 del = const_cpu_to_le16(SECTOR_DELETED);
+ u16 del = cpu_to_le16(SECTOR_DELETED);
block = old_addr / part->block_size;
offset = (old_addr % part->block_size) / SECTOR_SIZE -
@@ -763,7 +762,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{
struct partition *part;
- if (mtd->type != MTD_NORFLASH)
+ if (mtd->type != MTD_NORFLASH || mtd->size > UINT_MAX)
return;
part = kzalloc(sizeof(struct partition), GFP_KERNEL);
diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c
index 33a5d6ed6f18..3f67e00d98e0 100644
--- a/drivers/mtd/ssfdc.c
+++ b/drivers/mtd/ssfdc.c
@@ -294,7 +294,8 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
int cis_sector;
/* Check for small page NAND flash */
- if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE)
+ if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE ||
+ mtd->size > UINT_MAX)
return;
/* Check for SSDFC format by reading CIS/IDI sector */
@@ -316,7 +317,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
ssfdc->cis_block = cis_sector / (mtd->erasesize >> SECTOR_SHIFT);
ssfdc->erase_size = mtd->erasesize;
- ssfdc->map_len = mtd->size / mtd->erasesize;
+ ssfdc->map_len = (u32)mtd->size / mtd->erasesize;
DEBUG(MTD_DEBUG_LEVEL1,
"SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n",
@@ -327,7 +328,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
ssfdc->heads = 16;
ssfdc->sectors = 32;
get_chs(mtd->size, NULL, &ssfdc->heads, &ssfdc->sectors);
- ssfdc->cylinders = (unsigned short)((mtd->size >> SECTOR_SHIFT) /
+ ssfdc->cylinders = (unsigned short)(((u32)mtd->size >> SECTOR_SHIFT) /
((long)ssfdc->sectors * (long)ssfdc->heads));
DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n",
diff --git a/drivers/mtd/tests/Makefile b/drivers/mtd/tests/Makefile
new file mode 100644
index 000000000000..c1d501335006
--- /dev/null
+++ b/drivers/mtd/tests/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_MTD_TESTS) += mtd_oobtest.o
+obj-$(CONFIG_MTD_TESTS) += mtd_pagetest.o
+obj-$(CONFIG_MTD_TESTS) += mtd_readtest.o
+obj-$(CONFIG_MTD_TESTS) += mtd_speedtest.o
+obj-$(CONFIG_MTD_TESTS) += mtd_stresstest.o
+obj-$(CONFIG_MTD_TESTS) += mtd_subpagetest.o
+obj-$(CONFIG_MTD_TESTS) += mtd_torturetest.o
diff --git a/drivers/mtd/tests/mtd_oobtest.c b/drivers/mtd/tests/mtd_oobtest.c
new file mode 100644
index 000000000000..afbc3f8126db
--- /dev/null
+++ b/drivers/mtd/tests/mtd_oobtest.c
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Test OOB read and write on MTD device.
+ *
+ * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
+ */
+
+#include <asm/div64.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/sched.h>
+
+#define PRINT_PREF KERN_INFO "mtd_oobtest: "
+
+static int dev;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static struct mtd_info *mtd;
+static unsigned char *readbuf;
+static unsigned char *writebuf;
+static unsigned char *bbt;
+
+static int ebcnt;
+static int pgcnt;
+static int errcnt;
+static int use_offset;
+static int use_len;
+static int use_len_max;
+static int vary_offset;
+static unsigned long next = 1;
+
+static inline unsigned int simple_rand(void)
+{
+ next = next * 1103515245 + 12345;
+ return (unsigned int)((next / 65536) % 32768);
+}
+
+static inline void simple_srand(unsigned long seed)
+{
+ next = seed;
+}
+
+static void set_random_data(unsigned char *buf, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; ++i)
+ buf[i] = simple_rand();
+}
+
+static int erase_eraseblock(int ebnum)
+{
+ int err;
+ struct erase_info ei;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ memset(&ei, 0, sizeof(struct erase_info));
+ ei.mtd = mtd;
+ ei.addr = addr;
+ ei.len = mtd->erasesize;
+
+ err = mtd->erase(mtd, &ei);
+ if (err) {
+ printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+ return err;
+ }
+
+ if (ei.state == MTD_ERASE_FAILED) {
+ printk(PRINT_PREF "some erase error occurred at EB %d\n",
+ ebnum);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int erase_whole_device(void)
+{
+ int err;
+ unsigned int i;
+
+ printk(PRINT_PREF "erasing whole device\n");
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = erase_eraseblock(i);
+ if (err)
+ return err;
+ cond_resched();
+ }
+ printk(PRINT_PREF "erased %u eraseblocks\n", i);
+ return 0;
+}
+
+static void do_vary_offset(void)
+{
+ use_len -= 1;
+ if (use_len < 1) {
+ use_offset += 1;
+ if (use_offset >= use_len_max)
+ use_offset = 0;
+ use_len = use_len_max - use_offset;
+ }
+}
+
+static int write_eraseblock(int ebnum)
+{
+ int i;
+ struct mtd_oob_ops ops;
+ int err = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
+ set_random_data(writebuf, use_len);
+ ops.mode = MTD_OOB_AUTO;
+ ops.len = 0;
+ ops.retlen = 0;
+ ops.ooblen = use_len;
+ ops.oobretlen = 0;
+ ops.ooboffs = use_offset;
+ ops.datbuf = 0;
+ ops.oobbuf = writebuf;
+ err = mtd->write_oob(mtd, addr, &ops);
+ if (err || ops.oobretlen != use_len) {
+ printk(PRINT_PREF "error: writeoob failed at %#llx\n",
+ (long long)addr);
+ printk(PRINT_PREF "error: use_len %d, use_offset %d\n",
+ use_len, use_offset);
+ errcnt += 1;
+ return err ? err : -1;
+ }
+ if (vary_offset)
+ do_vary_offset();
+ }
+
+ return err;
+}
+
+static int write_whole_device(void)
+{
+ int err;
+ unsigned int i;
+
+ printk(PRINT_PREF "writing OOBs of whole device\n");
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = write_eraseblock(i);
+ if (err)
+ return err;
+ if (i % 256 == 0)
+ printk(PRINT_PREF "written up to eraseblock %u\n", i);
+ cond_resched();
+ }
+ printk(PRINT_PREF "written %u eraseblocks\n", i);
+ return 0;
+}
+
+static int verify_eraseblock(int ebnum)
+{
+ int i;
+ struct mtd_oob_ops ops;
+ int err = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
+ set_random_data(writebuf, use_len);
+ ops.mode = MTD_OOB_AUTO;
+ ops.len = 0;
+ ops.retlen = 0;
+ ops.ooblen = use_len;
+ ops.oobretlen = 0;
+ ops.ooboffs = use_offset;
+ ops.datbuf = 0;
+ ops.oobbuf = readbuf;
+ err = mtd->read_oob(mtd, addr, &ops);
+ if (err || ops.oobretlen != use_len) {
+ printk(PRINT_PREF "error: readoob failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+ return err ? err : -1;
+ }
+ if (memcmp(readbuf, writebuf, use_len)) {
+ printk(PRINT_PREF "error: verify failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+ if (errcnt > 1000) {
+ printk(PRINT_PREF "error: too many errors\n");
+ return -1;
+ }
+ }
+ if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {
+ int k;
+
+ ops.mode = MTD_OOB_AUTO;
+ ops.len = 0;
+ ops.retlen = 0;
+ ops.ooblen = mtd->ecclayout->oobavail;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = 0;
+ ops.oobbuf = readbuf;
+ err = mtd->read_oob(mtd, addr, &ops);
+ if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
+ printk(PRINT_PREF "error: readoob failed at "
+ "%#llx\n", (long long)addr);
+ errcnt += 1;
+ return err ? err : -1;
+ }
+ if (memcmp(readbuf + use_offset, writebuf, use_len)) {
+ printk(PRINT_PREF "error: verify failed at "
+ "%#llx\n", (long long)addr);
+ errcnt += 1;
+ if (errcnt > 1000) {
+ printk(PRINT_PREF "error: too many "
+ "errors\n");
+ return -1;
+ }
+ }
+ for (k = 0; k < use_offset; ++k)
+ if (readbuf[k] != 0xff) {
+ printk(PRINT_PREF "error: verify 0xff "
+ "failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+ if (errcnt > 1000) {
+ printk(PRINT_PREF "error: too "
+ "many errors\n");
+ return -1;
+ }
+ }
+ for (k = use_offset + use_len;
+ k < mtd->ecclayout->oobavail; ++k)
+ if (readbuf[k] != 0xff) {
+ printk(PRINT_PREF "error: verify 0xff "
+ "failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+ if (errcnt > 1000) {
+ printk(PRINT_PREF "error: too "
+ "many errors\n");
+ return -1;
+ }
+ }
+ }
+ if (vary_offset)
+ do_vary_offset();
+ }
+ return err;
+}
+
+static int verify_eraseblock_in_one_go(int ebnum)
+{
+ struct mtd_oob_ops ops;
+ int err = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+ size_t len = mtd->ecclayout->oobavail * pgcnt;
+
+ set_random_data(writebuf, len);
+ ops.mode = MTD_OOB_AUTO;
+ ops.len = 0;
+ ops.retlen = 0;
+ ops.ooblen = len;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = 0;
+ ops.oobbuf = readbuf;
+ err = mtd->read_oob(mtd, addr, &ops);
+ if (err || ops.oobretlen != len) {
+ printk(PRINT_PREF "error: readoob failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+ return err ? err : -1;
+ }
+ if (memcmp(readbuf, writebuf, len)) {
+ printk(PRINT_PREF "error: verify failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+ if (errcnt > 1000) {
+ printk(PRINT_PREF "error: too many errors\n");
+ return -1;
+ }
+ }
+
+ return err;
+}
+
+static int verify_all_eraseblocks(void)
+{
+ int err;
+ unsigned int i;
+
+ printk(PRINT_PREF "verifying all eraseblocks\n");
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = verify_eraseblock(i);
+ if (err)
+ return err;
+ if (i % 256 == 0)
+ printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+ cond_resched();
+ }
+ printk(PRINT_PREF "verified %u eraseblocks\n", i);
+ return 0;
+}
+
+static int is_block_bad(int ebnum)
+{
+ int ret;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ ret = mtd->block_isbad(mtd, addr);
+ if (ret)
+ printk(PRINT_PREF "block %d is bad\n", ebnum);
+ return ret;
+}
+
+static int scan_for_bad_eraseblocks(void)
+{
+ int i, bad = 0;
+
+ bbt = kmalloc(ebcnt, GFP_KERNEL);
+ if (!bbt) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ return -ENOMEM;
+ }
+ memset(bbt, 0 , ebcnt);
+
+ printk(PRINT_PREF "scanning for bad eraseblocks\n");
+ for (i = 0; i < ebcnt; ++i) {
+ bbt[i] = is_block_bad(i) ? 1 : 0;
+ if (bbt[i])
+ bad += 1;
+ cond_resched();
+ }
+ printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+ return 0;
+}
+
+static int __init mtd_oobtest_init(void)
+{
+ int err = 0;
+ unsigned int i;
+ uint64_t tmp;
+ struct mtd_oob_ops ops;
+ loff_t addr = 0, addr0;
+
+ printk(KERN_INFO "\n");
+ printk(KERN_INFO "=================================================\n");
+ printk(PRINT_PREF "MTD device: %d\n", dev);
+
+ mtd = get_mtd_device(NULL, dev);
+ if (IS_ERR(mtd)) {
+ err = PTR_ERR(mtd);
+ printk(PRINT_PREF "error: cannot get MTD device\n");
+ return err;
+ }
+
+ if (mtd->type != MTD_NANDFLASH) {
+ printk(PRINT_PREF "this test requires NAND flash\n");
+ goto out;
+ }
+
+ tmp = mtd->size;
+ do_div(tmp, mtd->erasesize);
+ ebcnt = tmp;
+ pgcnt = mtd->erasesize / mtd->writesize;
+
+ printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+ "page size %u, count of eraseblocks %u, pages per "
+ "eraseblock %u, OOB size %u\n",
+ (unsigned long long)mtd->size, mtd->erasesize,
+ mtd->writesize, ebcnt, pgcnt, mtd->oobsize);
+
+ err = -ENOMEM;
+ mtd->erasesize = mtd->erasesize;
+ readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
+ if (!readbuf) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out;
+ }
+ writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
+ if (!writebuf) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out;
+ }
+
+ err = scan_for_bad_eraseblocks();
+ if (err)
+ goto out;
+
+ use_offset = 0;
+ use_len = mtd->ecclayout->oobavail;
+ use_len_max = mtd->ecclayout->oobavail;
+ vary_offset = 0;
+
+ /* First test: write all OOB, read it back and verify */
+ printk(PRINT_PREF "test 1 of 5\n");
+
+ err = erase_whole_device();
+ if (err)
+ goto out;
+
+ simple_srand(1);
+ err = write_whole_device();
+ if (err)
+ goto out;
+
+ simple_srand(1);
+ err = verify_all_eraseblocks();
+ if (err)
+ goto out;
+
+ /*
+ * Second test: write all OOB, a block at a time, read it back and
+ * verify.
+ */
+ printk(PRINT_PREF "test 2 of 5\n");
+
+ err = erase_whole_device();
+ if (err)
+ goto out;
+
+ simple_srand(3);
+ err = write_whole_device();
+ if (err)
+ goto out;
+
+ /* Check all eraseblocks */
+ simple_srand(3);
+ printk(PRINT_PREF "verifying all eraseblocks\n");
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = verify_eraseblock_in_one_go(i);
+ if (err)
+ goto out;
+ if (i % 256 == 0)
+ printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+ cond_resched();
+ }
+ printk(PRINT_PREF "verified %u eraseblocks\n", i);
+
+ /*
+ * Third test: write OOB at varying offsets and lengths, read it back
+ * and verify.
+ */
+ printk(PRINT_PREF "test 3 of 5\n");
+
+ err = erase_whole_device();
+ if (err)
+ goto out;
+
+ /* Write all eraseblocks */
+ use_offset = 0;
+ use_len = mtd->ecclayout->oobavail;
+ use_len_max = mtd->ecclayout->oobavail;
+ vary_offset = 1;
+ simple_srand(5);
+ printk(PRINT_PREF "writing OOBs of whole device\n");
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = write_eraseblock(i);
+ if (err)
+ goto out;
+ if (i % 256 == 0)
+ printk(PRINT_PREF "written up to eraseblock %u\n", i);
+ cond_resched();
+ }
+ printk(PRINT_PREF "written %u eraseblocks\n", i);
+
+ /* Check all eraseblocks */
+ use_offset = 0;
+ use_len = mtd->ecclayout->oobavail;
+ use_len_max = mtd->ecclayout->oobavail;
+ vary_offset = 1;
+ simple_srand(5);
+ err = verify_all_eraseblocks();
+ if (err)
+ goto out;
+
+ use_offset = 0;
+ use_len = mtd->ecclayout->oobavail;
+ use_len_max = mtd->ecclayout->oobavail;
+ vary_offset = 0;
+
+ /* Fourth test: try to write off end of device */
+ printk(PRINT_PREF "test 4 of 5\n");
+
+ err = erase_whole_device();
+ if (err)
+ goto out;
+
+ addr0 = 0;
+ for (i = 0; bbt[i] && i < ebcnt; ++i)
+ addr0 += mtd->erasesize;
+
+ /* Attempt to write off end of OOB */
+ ops.mode = MTD_OOB_AUTO;
+ ops.len = 0;
+ ops.retlen = 0;
+ ops.ooblen = 1;
+ ops.oobretlen = 0;
+ ops.ooboffs = mtd->ecclayout->oobavail;
+ ops.datbuf = 0;
+ ops.oobbuf = writebuf;
+ printk(PRINT_PREF "attempting to start write past end of OOB\n");
+ printk(PRINT_PREF "an error is expected...\n");
+ err = mtd->write_oob(mtd, addr0, &ops);
+ if (err) {
+ printk(PRINT_PREF "error occurred as expected\n");
+ err = 0;
+ } else {
+ printk(PRINT_PREF "error: can write past end of OOB\n");
+ errcnt += 1;
+ }
+
+ /* Attempt to read off end of OOB */
+ ops.mode = MTD_OOB_AUTO;
+ ops.len = 0;
+ ops.retlen = 0;
+ ops.ooblen = 1;
+ ops.oobretlen = 0;
+ ops.ooboffs = mtd->ecclayout->oobavail;
+ ops.datbuf = 0;
+ ops.oobbuf = readbuf;
+ printk(PRINT_PREF "attempting to start read past end of OOB\n");
+ printk(PRINT_PREF "an error is expected...\n");
+ err = mtd->read_oob(mtd, addr0, &ops);
+ if (err) {
+ printk(PRINT_PREF "error occurred as expected\n");
+ err = 0;
+ } else {
+ printk(PRINT_PREF "error: can read past end of OOB\n");
+ errcnt += 1;
+ }
+
+ if (bbt[ebcnt - 1])
+ printk(PRINT_PREF "skipping end of device tests because last "
+ "block is bad\n");
+ else {
+ /* Attempt to write off end of device */
+ ops.mode = MTD_OOB_AUTO;
+ ops.len = 0;
+ ops.retlen = 0;
+ ops.ooblen = mtd->ecclayout->oobavail + 1;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = 0;
+ ops.oobbuf = writebuf;
+ printk(PRINT_PREF "attempting to write past end of device\n");
+ printk(PRINT_PREF "an error is expected...\n");
+ err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops);
+ if (err) {
+ printk(PRINT_PREF "error occurred as expected\n");
+ err = 0;
+ } else {
+ printk(PRINT_PREF "error: wrote past end of device\n");
+ errcnt += 1;
+ }
+
+ /* Attempt to read off end of device */
+ ops.mode = MTD_OOB_AUTO;
+ ops.len = 0;
+ ops.retlen = 0;
+ ops.ooblen = mtd->ecclayout->oobavail + 1;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = 0;
+ ops.oobbuf = readbuf;
+ printk(PRINT_PREF "attempting to read past end of device\n");
+ printk(PRINT_PREF "an error is expected...\n");
+ err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops);
+ if (err) {
+ printk(PRINT_PREF "error occurred as expected\n");
+ err = 0;
+ } else {
+ printk(PRINT_PREF "error: read past end of device\n");
+ errcnt += 1;
+ }
+
+ err = erase_eraseblock(ebcnt - 1);
+ if (err)
+ goto out;
+
+ /* Attempt to write off end of device */
+ ops.mode = MTD_OOB_AUTO;
+ ops.len = 0;
+ ops.retlen = 0;
+ ops.ooblen = mtd->ecclayout->oobavail;
+ ops.oobretlen = 0;
+ ops.ooboffs = 1;
+ ops.datbuf = 0;
+ ops.oobbuf = writebuf;
+ printk(PRINT_PREF "attempting to write past end of device\n");
+ printk(PRINT_PREF "an error is expected...\n");
+ err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops);
+ if (err) {
+ printk(PRINT_PREF "error occurred as expected\n");
+ err = 0;
+ } else {
+ printk(PRINT_PREF "error: wrote past end of device\n");
+ errcnt += 1;
+ }
+
+ /* Attempt to read off end of device */
+ ops.mode = MTD_OOB_AUTO;
+ ops.len = 0;
+ ops.retlen = 0;
+ ops.ooblen = mtd->ecclayout->oobavail;
+ ops.oobretlen = 0;
+ ops.ooboffs = 1;
+ ops.datbuf = 0;
+ ops.oobbuf = readbuf;
+ printk(PRINT_PREF "attempting to read past end of device\n");
+ printk(PRINT_PREF "an error is expected...\n");
+ err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops);
+ if (err) {
+ printk(PRINT_PREF "error occurred as expected\n");
+ err = 0;
+ } else {
+ printk(PRINT_PREF "error: read past end of device\n");
+ errcnt += 1;
+ }
+ }
+
+ /* Fifth test: write / read across block boundaries */
+ printk(PRINT_PREF "test 5 of 5\n");
+
+ /* Erase all eraseblocks */
+ err = erase_whole_device();
+ if (err)
+ goto out;
+
+ /* Write all eraseblocks */
+ simple_srand(11);
+ printk(PRINT_PREF "writing OOBs of whole device\n");
+ for (i = 0; i < ebcnt - 1; ++i) {
+ int cnt = 2;
+ int pg;
+ size_t sz = mtd->ecclayout->oobavail;
+ if (bbt[i] || bbt[i + 1])
+ continue;
+ addr = (i + 1) * mtd->erasesize - mtd->writesize;
+ for (pg = 0; pg < cnt; ++pg) {
+ set_random_data(writebuf, sz);
+ ops.mode = MTD_OOB_AUTO;
+ ops.len = 0;
+ ops.retlen = 0;
+ ops.ooblen = sz;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = 0;
+ ops.oobbuf = writebuf;
+ err = mtd->write_oob(mtd, addr, &ops);
+ if (err)
+ goto out;
+ if (i % 256 == 0)
+ printk(PRINT_PREF "written up to eraseblock "
+ "%u\n", i);
+ cond_resched();
+ addr += mtd->writesize;
+ }
+ }
+ printk(PRINT_PREF "written %u eraseblocks\n", i);
+
+ /* Check all eraseblocks */
+ simple_srand(11);
+ printk(PRINT_PREF "verifying all eraseblocks\n");
+ for (i = 0; i < ebcnt - 1; ++i) {
+ if (bbt[i] || bbt[i + 1])
+ continue;
+ set_random_data(writebuf, mtd->ecclayout->oobavail * 2);
+ addr = (i + 1) * mtd->erasesize - mtd->writesize;
+ ops.mode = MTD_OOB_AUTO;
+ ops.len = 0;
+ ops.retlen = 0;
+ ops.ooblen = mtd->ecclayout->oobavail * 2;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = 0;
+ ops.oobbuf = readbuf;
+ err = mtd->read_oob(mtd, addr, &ops);
+ if (err)
+ goto out;
+ if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) {
+ printk(PRINT_PREF "error: verify failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+ if (errcnt > 1000) {
+ printk(PRINT_PREF "error: too many errors\n");
+ goto out;
+ }
+ }
+ if (i % 256 == 0)
+ printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+ cond_resched();
+ }
+ printk(PRINT_PREF "verified %u eraseblocks\n", i);
+
+ printk(PRINT_PREF "finished with %d errors\n", errcnt);
+out:
+ kfree(bbt);
+ kfree(writebuf);
+ kfree(readbuf);
+ put_mtd_device(mtd);
+ if (err)
+ printk(PRINT_PREF "error %d occurred\n", err);
+ printk(KERN_INFO "=================================================\n");
+ return err;
+}
+module_init(mtd_oobtest_init);
+
+static void __exit mtd_oobtest_exit(void)
+{
+ return;
+}
+module_exit(mtd_oobtest_exit);
+
+MODULE_DESCRIPTION("Out-of-band test module");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c
new file mode 100644
index 000000000000..9648818b9e2c
--- /dev/null
+++ b/drivers/mtd/tests/mtd_pagetest.c
@@ -0,0 +1,632 @@
+/*
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Test page read and write on MTD device.
+ *
+ * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
+ */
+
+#include <asm/div64.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/sched.h>
+
+#define PRINT_PREF KERN_INFO "mtd_pagetest: "
+
+static int dev;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static struct mtd_info *mtd;
+static unsigned char *twopages;
+static unsigned char *writebuf;
+static unsigned char *boundary;
+static unsigned char *bbt;
+
+static int pgsize;
+static int bufsize;
+static int ebcnt;
+static int pgcnt;
+static int errcnt;
+static unsigned long next = 1;
+
+static inline unsigned int simple_rand(void)
+{
+ next = next * 1103515245 + 12345;
+ return (unsigned int)((next / 65536) % 32768);
+}
+
+static inline void simple_srand(unsigned long seed)
+{
+ next = seed;
+}
+
+static void set_random_data(unsigned char *buf, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; ++i)
+ buf[i] = simple_rand();
+}
+
+static int erase_eraseblock(int ebnum)
+{
+ int err;
+ struct erase_info ei;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ memset(&ei, 0, sizeof(struct erase_info));
+ ei.mtd = mtd;
+ ei.addr = addr;
+ ei.len = mtd->erasesize;
+
+ err = mtd->erase(mtd, &ei);
+ if (err) {
+ printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+ return err;
+ }
+
+ if (ei.state == MTD_ERASE_FAILED) {
+ printk(PRINT_PREF "some erase error occurred at EB %d\n",
+ ebnum);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int write_eraseblock(int ebnum)
+{
+ int err = 0;
+ size_t written = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ set_random_data(writebuf, mtd->erasesize);
+ cond_resched();
+ err = mtd->write(mtd, addr, mtd->erasesize, &written, writebuf);
+ if (err || written != mtd->erasesize)
+ printk(PRINT_PREF "error: write failed at %#llx\n",
+ (long long)addr);
+
+ return err;
+}
+
+static int verify_eraseblock(int ebnum)
+{
+ uint32_t j;
+ size_t read = 0;
+ int err = 0, i;
+ loff_t addr0, addrn;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ addr0 = 0;
+ for (i = 0; bbt[i] && i < ebcnt; ++i)
+ addr0 += mtd->erasesize;
+
+ addrn = mtd->size;
+ for (i = 0; bbt[ebcnt - i - 1] && i < ebcnt; ++i)
+ addrn -= mtd->erasesize;
+
+ set_random_data(writebuf, mtd->erasesize);
+ for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
+ /* Do a read to set the internal dataRAMs to different data */
+ err = mtd->read(mtd, addr0, bufsize, &read, twopages);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != bufsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr0);
+ return err;
+ }
+ err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != bufsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)(addrn - bufsize));
+ return err;
+ }
+ memset(twopages, 0, bufsize);
+ read = 0;
+ err = mtd->read(mtd, addr, bufsize, &read, twopages);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != bufsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr);
+ break;
+ }
+ if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
+ printk(PRINT_PREF "error: verify failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+ }
+ }
+ /* Check boundary between eraseblocks */
+ if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) {
+ unsigned long oldnext = next;
+ /* Do a read to set the internal dataRAMs to different data */
+ err = mtd->read(mtd, addr0, bufsize, &read, twopages);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != bufsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr0);
+ return err;
+ }
+ err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != bufsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)(addrn - bufsize));
+ return err;
+ }
+ memset(twopages, 0, bufsize);
+ read = 0;
+ err = mtd->read(mtd, addr, bufsize, &read, twopages);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != bufsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr);
+ return err;
+ }
+ memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
+ set_random_data(boundary + pgsize, pgsize);
+ if (memcmp(twopages, boundary, bufsize)) {
+ printk(PRINT_PREF "error: verify failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+ }
+ next = oldnext;
+ }
+ return err;
+}
+
+static int crosstest(void)
+{
+ size_t read = 0;
+ int err = 0, i;
+ loff_t addr, addr0, addrn;
+ unsigned char *pp1, *pp2, *pp3, *pp4;
+
+ printk(PRINT_PREF "crosstest\n");
+ pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
+ if (!pp1) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ return -ENOMEM;
+ }
+ pp2 = pp1 + pgsize;
+ pp3 = pp2 + pgsize;
+ pp4 = pp3 + pgsize;
+ memset(pp1, 0, pgsize * 4);
+
+ addr0 = 0;
+ for (i = 0; bbt[i] && i < ebcnt; ++i)
+ addr0 += mtd->erasesize;
+
+ addrn = mtd->size;
+ for (i = 0; bbt[ebcnt - i - 1] && i < ebcnt; ++i)
+ addrn -= mtd->erasesize;
+
+ /* Read 2nd-to-last page to pp1 */
+ read = 0;
+ addr = addrn - pgsize - pgsize;
+ err = mtd->read(mtd, addr, pgsize, &read, pp1);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != pgsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr);
+ kfree(pp1);
+ return err;
+ }
+
+ /* Read 3rd-to-last page to pp1 */
+ read = 0;
+ addr = addrn - pgsize - pgsize - pgsize;
+ err = mtd->read(mtd, addr, pgsize, &read, pp1);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != pgsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr);
+ kfree(pp1);
+ return err;
+ }
+
+ /* Read first page to pp2 */
+ read = 0;
+ addr = addr0;
+ printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
+ err = mtd->read(mtd, addr, pgsize, &read, pp2);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != pgsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr);
+ kfree(pp1);
+ return err;
+ }
+
+ /* Read last page to pp3 */
+ read = 0;
+ addr = addrn - pgsize;
+ printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
+ err = mtd->read(mtd, addr, pgsize, &read, pp3);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != pgsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr);
+ kfree(pp1);
+ return err;
+ }
+
+ /* Read first page again to pp4 */
+ read = 0;
+ addr = addr0;
+ printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
+ err = mtd->read(mtd, addr, pgsize, &read, pp4);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != pgsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr);
+ kfree(pp1);
+ return err;
+ }
+
+ /* pp2 and pp4 should be the same */
+ printk(PRINT_PREF "verifying pages read at %#llx match\n",
+ (long long)addr0);
+ if (memcmp(pp2, pp4, pgsize)) {
+ printk(PRINT_PREF "verify failed!\n");
+ errcnt += 1;
+ } else if (!err)
+ printk(PRINT_PREF "crosstest ok\n");
+ kfree(pp1);
+ return err;
+}
+
+static int erasecrosstest(void)
+{
+ size_t read = 0, written = 0;
+ int err = 0, i, ebnum, ok = 1, ebnum2;
+ loff_t addr0;
+ char *readbuf = twopages;
+
+ printk(PRINT_PREF "erasecrosstest\n");
+
+ ebnum = 0;
+ addr0 = 0;
+ for (i = 0; bbt[i] && i < ebcnt; ++i) {
+ addr0 += mtd->erasesize;
+ ebnum += 1;
+ }
+
+ ebnum2 = ebcnt - 1;
+ while (ebnum2 && bbt[ebnum2])
+ ebnum2 -= 1;
+
+ printk(PRINT_PREF "erasing block %d\n", ebnum);
+ err = erase_eraseblock(ebnum);
+ if (err)
+ return err;
+
+ printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
+ set_random_data(writebuf, pgsize);
+ strcpy(writebuf, "There is no data like this!");
+ err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
+ if (err || written != pgsize) {
+ printk(PRINT_PREF "error: write failed at %#llx\n",
+ (long long)addr0);
+ return err ? err : -1;
+ }
+
+ printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
+ memset(readbuf, 0, pgsize);
+ err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != pgsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr0);
+ return err ? err : -1;
+ }
+
+ printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
+ if (memcmp(writebuf, readbuf, pgsize)) {
+ printk(PRINT_PREF "verify failed!\n");
+ errcnt += 1;
+ ok = 0;
+ return err;
+ }
+
+ printk(PRINT_PREF "erasing block %d\n", ebnum);
+ err = erase_eraseblock(ebnum);
+ if (err)
+ return err;
+
+ printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
+ set_random_data(writebuf, pgsize);
+ strcpy(writebuf, "There is no data like this!");
+ err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
+ if (err || written != pgsize) {
+ printk(PRINT_PREF "error: write failed at %#llx\n",
+ (long long)addr0);
+ return err ? err : -1;
+ }
+
+ printk(PRINT_PREF "erasing block %d\n", ebnum2);
+ err = erase_eraseblock(ebnum2);
+ if (err)
+ return err;
+
+ printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
+ memset(readbuf, 0, pgsize);
+ err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != pgsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr0);
+ return err ? err : -1;
+ }
+
+ printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
+ if (memcmp(writebuf, readbuf, pgsize)) {
+ printk(PRINT_PREF "verify failed!\n");
+ errcnt += 1;
+ ok = 0;
+ }
+
+ if (ok && !err)
+ printk(PRINT_PREF "erasecrosstest ok\n");
+ return err;
+}
+
+static int erasetest(void)
+{
+ size_t read = 0, written = 0;
+ int err = 0, i, ebnum, ok = 1;
+ loff_t addr0;
+
+ printk(PRINT_PREF "erasetest\n");
+
+ ebnum = 0;
+ addr0 = 0;
+ for (i = 0; bbt[i] && i < ebcnt; ++i) {
+ addr0 += mtd->erasesize;
+ ebnum += 1;
+ }
+
+ printk(PRINT_PREF "erasing block %d\n", ebnum);
+ err = erase_eraseblock(ebnum);
+ if (err)
+ return err;
+
+ printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
+ set_random_data(writebuf, pgsize);
+ err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
+ if (err || written != pgsize) {
+ printk(PRINT_PREF "error: write failed at %#llx\n",
+ (long long)addr0);
+ return err ? err : -1;
+ }
+
+ printk(PRINT_PREF "erasing block %d\n", ebnum);
+ err = erase_eraseblock(ebnum);
+ if (err)
+ return err;
+
+ printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
+ err = mtd->read(mtd, addr0, pgsize, &read, twopages);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != pgsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr0);
+ return err ? err : -1;
+ }
+
+ printk(PRINT_PREF "verifying 1st page of block %d is all 0xff\n",
+ ebnum);
+ for (i = 0; i < pgsize; ++i)
+ if (twopages[i] != 0xff) {
+ printk(PRINT_PREF "verifying all 0xff failed at %d\n",
+ i);
+ errcnt += 1;
+ ok = 0;
+ break;
+ }
+
+ if (ok && !err)
+ printk(PRINT_PREF "erasetest ok\n");
+
+ return err;
+}
+
+static int is_block_bad(int ebnum)
+{
+ loff_t addr = ebnum * mtd->erasesize;
+ int ret;
+
+ ret = mtd->block_isbad(mtd, addr);
+ if (ret)
+ printk(PRINT_PREF "block %d is bad\n", ebnum);
+ return ret;
+}
+
+static int scan_for_bad_eraseblocks(void)
+{
+ int i, bad = 0;
+
+ bbt = kmalloc(ebcnt, GFP_KERNEL);
+ if (!bbt) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ return -ENOMEM;
+ }
+ memset(bbt, 0 , ebcnt);
+
+ printk(PRINT_PREF "scanning for bad eraseblocks\n");
+ for (i = 0; i < ebcnt; ++i) {
+ bbt[i] = is_block_bad(i) ? 1 : 0;
+ if (bbt[i])
+ bad += 1;
+ cond_resched();
+ }
+ printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+ return 0;
+}
+
+static int __init mtd_pagetest_init(void)
+{
+ int err = 0;
+ uint64_t tmp;
+ uint32_t i;
+
+ printk(KERN_INFO "\n");
+ printk(KERN_INFO "=================================================\n");
+ printk(PRINT_PREF "MTD device: %d\n", dev);
+
+ mtd = get_mtd_device(NULL, dev);
+ if (IS_ERR(mtd)) {
+ err = PTR_ERR(mtd);
+ printk(PRINT_PREF "error: cannot get MTD device\n");
+ return err;
+ }
+
+ if (mtd->type != MTD_NANDFLASH) {
+ printk(PRINT_PREF "this test requires NAND flash\n");
+ goto out;
+ }
+
+ tmp = mtd->size;
+ do_div(tmp, mtd->erasesize);
+ ebcnt = tmp;
+ pgcnt = mtd->erasesize / mtd->writesize;
+
+ printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+ "page size %u, count of eraseblocks %u, pages per "
+ "eraseblock %u, OOB size %u\n",
+ (unsigned long long)mtd->size, mtd->erasesize,
+ pgsize, ebcnt, pgcnt, mtd->oobsize);
+
+ err = -ENOMEM;
+ bufsize = pgsize * 2;
+ writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
+ if (!writebuf) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out;
+ }
+ twopages = kmalloc(bufsize, GFP_KERNEL);
+ if (!twopages) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out;
+ }
+ boundary = kmalloc(bufsize, GFP_KERNEL);
+ if (!boundary) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out;
+ }
+
+ err = scan_for_bad_eraseblocks();
+ if (err)
+ goto out;
+
+ /* Erase all eraseblocks */
+ printk(PRINT_PREF "erasing whole device\n");
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = erase_eraseblock(i);
+ if (err)
+ goto out;
+ cond_resched();
+ }
+ printk(PRINT_PREF "erased %u eraseblocks\n", i);
+
+ /* Write all eraseblocks */
+ simple_srand(1);
+ printk(PRINT_PREF "writing whole device\n");
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = write_eraseblock(i);
+ if (err)
+ goto out;
+ if (i % 256 == 0)
+ printk(PRINT_PREF "written up to eraseblock %u\n", i);
+ cond_resched();
+ }
+ printk(PRINT_PREF "written %u eraseblocks\n", i);
+
+ /* Check all eraseblocks */
+ simple_srand(1);
+ printk(PRINT_PREF "verifying all eraseblocks\n");
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = verify_eraseblock(i);
+ if (err)
+ goto out;
+ if (i % 256 == 0)
+ printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+ cond_resched();
+ }
+ printk(PRINT_PREF "verified %u eraseblocks\n", i);
+
+ err = crosstest();
+ if (err)
+ goto out;
+
+ err = erasecrosstest();
+ if (err)
+ goto out;
+
+ err = erasetest();
+ if (err)
+ goto out;
+
+ printk(PRINT_PREF "finished with %d errors\n", errcnt);
+out:
+
+ kfree(bbt);
+ kfree(boundary);
+ kfree(twopages);
+ kfree(writebuf);
+ put_mtd_device(mtd);
+ if (err)
+ printk(PRINT_PREF "error %d occurred\n", err);
+ printk(KERN_INFO "=================================================\n");
+ return err;
+}
+module_init(mtd_pagetest_init);
+
+static void __exit mtd_pagetest_exit(void)
+{
+ return;
+}
+module_exit(mtd_pagetest_exit);
+
+MODULE_DESCRIPTION("NAND page test");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c
new file mode 100644
index 000000000000..645e77fdc63d
--- /dev/null
+++ b/drivers/mtd/tests/mtd_readtest.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Check MTD device read.
+ *
+ * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/sched.h>
+
+#define PRINT_PREF KERN_INFO "mtd_readtest: "
+
+static int dev;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static struct mtd_info *mtd;
+static unsigned char *iobuf;
+static unsigned char *iobuf1;
+static unsigned char *bbt;
+
+static int pgsize;
+static int ebcnt;
+static int pgcnt;
+
+static int read_eraseblock_by_page(int ebnum)
+{
+ size_t read = 0;
+ int i, ret, err = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+ void *buf = iobuf;
+ void *oobbuf = iobuf1;
+
+ for (i = 0; i < pgcnt; i++) {
+ memset(buf, 0 , pgcnt);
+ ret = mtd->read(mtd, addr, pgsize, &read, buf);
+ if (ret == -EUCLEAN)
+ ret = 0;
+ if (ret || read != pgsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr);
+ if (!err)
+ err = ret;
+ if (!err)
+ err = -EINVAL;
+ }
+ if (mtd->oobsize) {
+ struct mtd_oob_ops ops;
+
+ ops.mode = MTD_OOB_PLACE;
+ ops.len = 0;
+ ops.retlen = 0;
+ ops.ooblen = mtd->oobsize;
+ ops.oobretlen = 0;
+ ops.ooboffs = 0;
+ ops.datbuf = 0;
+ ops.oobbuf = oobbuf;
+ ret = mtd->read_oob(mtd, addr, &ops);
+ if (ret || ops.oobretlen != mtd->oobsize) {
+ printk(PRINT_PREF "error: read oob failed at "
+ "%#llx\n", (long long)addr);
+ if (!err)
+ err = ret;
+ if (!err)
+ err = -EINVAL;
+ }
+ oobbuf += mtd->oobsize;
+ }
+ addr += pgsize;
+ buf += pgsize;
+ }
+
+ return err;
+}
+
+static void dump_eraseblock(int ebnum)
+{
+ int i, j, n;
+ char line[128];
+ int pg, oob;
+
+ printk(PRINT_PREF "dumping eraseblock %d\n", ebnum);
+ n = mtd->erasesize;
+ for (i = 0; i < n;) {
+ char *p = line;
+
+ p += sprintf(p, "%05x: ", i);
+ for (j = 0; j < 32 && i < n; j++, i++)
+ p += sprintf(p, "%02x", (unsigned int)iobuf[i]);
+ printk(KERN_CRIT "%s\n", line);
+ cond_resched();
+ }
+ if (!mtd->oobsize)
+ return;
+ printk(PRINT_PREF "dumping oob from eraseblock %d\n", ebnum);
+ n = mtd->oobsize;
+ for (pg = 0, i = 0; pg < pgcnt; pg++)
+ for (oob = 0; oob < n;) {
+ char *p = line;
+
+ p += sprintf(p, "%05x: ", i);
+ for (j = 0; j < 32 && oob < n; j++, oob++, i++)
+ p += sprintf(p, "%02x",
+ (unsigned int)iobuf1[i]);
+ printk(KERN_CRIT "%s\n", line);
+ cond_resched();
+ }
+}
+
+static int is_block_bad(int ebnum)
+{
+ loff_t addr = ebnum * mtd->erasesize;
+ int ret;
+
+ ret = mtd->block_isbad(mtd, addr);
+ if (ret)
+ printk(PRINT_PREF "block %d is bad\n", ebnum);
+ return ret;
+}
+
+static int scan_for_bad_eraseblocks(void)
+{
+ int i, bad = 0;
+
+ bbt = kmalloc(ebcnt, GFP_KERNEL);
+ if (!bbt) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ return -ENOMEM;
+ }
+ memset(bbt, 0 , ebcnt);
+
+ printk(PRINT_PREF "scanning for bad eraseblocks\n");
+ for (i = 0; i < ebcnt; ++i) {
+ bbt[i] = is_block_bad(i) ? 1 : 0;
+ if (bbt[i])
+ bad += 1;
+ cond_resched();
+ }
+ printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+ return 0;
+}
+
+static int __init mtd_readtest_init(void)
+{
+ uint64_t tmp;
+ int err, i;
+
+ printk(KERN_INFO "\n");
+ printk(KERN_INFO "=================================================\n");
+ printk(PRINT_PREF "MTD device: %d\n", dev);
+
+ mtd = get_mtd_device(NULL, dev);
+ if (IS_ERR(mtd)) {
+ err = PTR_ERR(mtd);
+ printk(PRINT_PREF "error: Cannot get MTD device\n");
+ return err;
+ }
+
+ if (mtd->writesize == 1) {
+ printk(PRINT_PREF "not NAND flash, assume page size is 512 "
+ "bytes.\n");
+ pgsize = 512;
+ } else
+ pgsize = mtd->writesize;
+
+ tmp = mtd->size;
+ do_div(tmp, mtd->erasesize);
+ ebcnt = tmp;
+ pgcnt = mtd->erasesize / mtd->writesize;
+
+ printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+ "page size %u, count of eraseblocks %u, pages per "
+ "eraseblock %u, OOB size %u\n",
+ (unsigned long long)mtd->size, mtd->erasesize,
+ pgsize, ebcnt, pgcnt, mtd->oobsize);
+
+ err = -ENOMEM;
+ iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
+ if (!iobuf) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out;
+ }
+ iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL);
+ if (!iobuf1) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out;
+ }
+
+ err = scan_for_bad_eraseblocks();
+ if (err)
+ goto out;
+
+ /* Read all eraseblocks 1 page at a time */
+ printk(PRINT_PREF "testing page read\n");
+ for (i = 0; i < ebcnt; ++i) {
+ int ret;
+
+ if (bbt[i])
+ continue;
+ ret = read_eraseblock_by_page(i);
+ if (ret) {
+ dump_eraseblock(i);
+ if (!err)
+ err = ret;
+ }
+ cond_resched();
+ }
+
+ if (err)
+ printk(PRINT_PREF "finished with errors\n");
+ else
+ printk(PRINT_PREF "finished\n");
+
+out:
+
+ kfree(iobuf);
+ kfree(iobuf1);
+ kfree(bbt);
+ put_mtd_device(mtd);
+ if (err)
+ printk(PRINT_PREF "error %d occurred\n", err);
+ printk(KERN_INFO "=================================================\n");
+ return err;
+}
+module_init(mtd_readtest_init);
+
+static void __exit mtd_readtest_exit(void)
+{
+ return;
+}
+module_exit(mtd_readtest_exit);
+
+MODULE_DESCRIPTION("Read test module");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c
new file mode 100644
index 000000000000..141363a7e805
--- /dev/null
+++ b/drivers/mtd/tests/mtd_speedtest.c
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Test read and write speed of a MTD device.
+ *
+ * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/sched.h>
+
+#define PRINT_PREF KERN_INFO "mtd_speedtest: "
+
+static int dev;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static struct mtd_info *mtd;
+static unsigned char *iobuf;
+static unsigned char *bbt;
+
+static int pgsize;
+static int ebcnt;
+static int pgcnt;
+static int goodebcnt;
+static struct timeval start, finish;
+static unsigned long next = 1;
+
+static inline unsigned int simple_rand(void)
+{
+ next = next * 1103515245 + 12345;
+ return (unsigned int)((next / 65536) % 32768);
+}
+
+static inline void simple_srand(unsigned long seed)
+{
+ next = seed;
+}
+
+static void set_random_data(unsigned char *buf, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; ++i)
+ buf[i] = simple_rand();
+}
+
+static int erase_eraseblock(int ebnum)
+{
+ int err;
+ struct erase_info ei;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ memset(&ei, 0, sizeof(struct erase_info));
+ ei.mtd = mtd;
+ ei.addr = addr;
+ ei.len = mtd->erasesize;
+
+ err = mtd->erase(mtd, &ei);
+ if (err) {
+ printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+ return err;
+ }
+
+ if (ei.state == MTD_ERASE_FAILED) {
+ printk(PRINT_PREF "some erase error occurred at EB %d\n",
+ ebnum);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int erase_whole_device(void)
+{
+ int err;
+ unsigned int i;
+
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = erase_eraseblock(i);
+ if (err)
+ return err;
+ cond_resched();
+ }
+ return 0;
+}
+
+static int write_eraseblock(int ebnum)
+{
+ size_t written = 0;
+ int err = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ err = mtd->write(mtd, addr, mtd->erasesize, &written, iobuf);
+ if (err || written != mtd->erasesize) {
+ printk(PRINT_PREF "error: write failed at %#llx\n", addr);
+ if (!err)
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static int write_eraseblock_by_page(int ebnum)
+{
+ size_t written = 0;
+ int i, err = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+ void *buf = iobuf;
+
+ for (i = 0; i < pgcnt; i++) {
+ err = mtd->write(mtd, addr, pgsize, &written, buf);
+ if (err || written != pgsize) {
+ printk(PRINT_PREF "error: write failed at %#llx\n",
+ addr);
+ if (!err)
+ err = -EINVAL;
+ break;
+ }
+ addr += pgsize;
+ buf += pgsize;
+ }
+
+ return err;
+}
+
+static int write_eraseblock_by_2pages(int ebnum)
+{
+ size_t written = 0, sz = pgsize * 2;
+ int i, n = pgcnt / 2, err = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+ void *buf = iobuf;
+
+ for (i = 0; i < n; i++) {
+ err = mtd->write(mtd, addr, sz, &written, buf);
+ if (err || written != sz) {
+ printk(PRINT_PREF "error: write failed at %#llx\n",
+ addr);
+ if (!err)
+ err = -EINVAL;
+ return err;
+ }
+ addr += sz;
+ buf += sz;
+ }
+ if (pgcnt % 2) {
+ err = mtd->write(mtd, addr, pgsize, &written, buf);
+ if (err || written != pgsize) {
+ printk(PRINT_PREF "error: write failed at %#llx\n",
+ addr);
+ if (!err)
+ err = -EINVAL;
+ }
+ }
+
+ return err;
+}
+
+static int read_eraseblock(int ebnum)
+{
+ size_t read = 0;
+ int err = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ err = mtd->read(mtd, addr, mtd->erasesize, &read, iobuf);
+ /* Ignore corrected ECC errors */
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != mtd->erasesize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n", addr);
+ if (!err)
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static int read_eraseblock_by_page(int ebnum)
+{
+ size_t read = 0;
+ int i, err = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+ void *buf = iobuf;
+
+ for (i = 0; i < pgcnt; i++) {
+ err = mtd->read(mtd, addr, pgsize, &read, buf);
+ /* Ignore corrected ECC errors */
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != pgsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ addr);
+ if (!err)
+ err = -EINVAL;
+ break;
+ }
+ addr += pgsize;
+ buf += pgsize;
+ }
+
+ return err;
+}
+
+static int read_eraseblock_by_2pages(int ebnum)
+{
+ size_t read = 0, sz = pgsize * 2;
+ int i, n = pgcnt / 2, err = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+ void *buf = iobuf;
+
+ for (i = 0; i < n; i++) {
+ err = mtd->read(mtd, addr, sz, &read, buf);
+ /* Ignore corrected ECC errors */
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != sz) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ addr);
+ if (!err)
+ err = -EINVAL;
+ return err;
+ }
+ addr += sz;
+ buf += sz;
+ }
+ if (pgcnt % 2) {
+ err = mtd->read(mtd, addr, pgsize, &read, buf);
+ /* Ignore corrected ECC errors */
+ if (err == -EUCLEAN)
+ err = 0;
+ if (err || read != pgsize) {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ addr);
+ if (!err)
+ err = -EINVAL;
+ }
+ }
+
+ return err;
+}
+
+static int is_block_bad(int ebnum)
+{
+ loff_t addr = ebnum * mtd->erasesize;
+ int ret;
+
+ ret = mtd->block_isbad(mtd, addr);
+ if (ret)
+ printk(PRINT_PREF "block %d is bad\n", ebnum);
+ return ret;
+}
+
+static inline void start_timing(void)
+{
+ do_gettimeofday(&start);
+}
+
+static inline void stop_timing(void)
+{
+ do_gettimeofday(&finish);
+}
+
+static long calc_speed(void)
+{
+ long ms, k, speed;
+
+ ms = (finish.tv_sec - start.tv_sec) * 1000 +
+ (finish.tv_usec - start.tv_usec) / 1000;
+ k = goodebcnt * mtd->erasesize / 1024;
+ speed = (k * 1000) / ms;
+ return speed;
+}
+
+static int scan_for_bad_eraseblocks(void)
+{
+ int i, bad = 0;
+
+ bbt = kmalloc(ebcnt, GFP_KERNEL);
+ if (!bbt) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ return -ENOMEM;
+ }
+ memset(bbt, 0 , ebcnt);
+
+ printk(PRINT_PREF "scanning for bad eraseblocks\n");
+ for (i = 0; i < ebcnt; ++i) {
+ bbt[i] = is_block_bad(i) ? 1 : 0;
+ if (bbt[i])
+ bad += 1;
+ cond_resched();
+ }
+ printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+ goodebcnt = ebcnt - bad;
+ return 0;
+}
+
+static int __init mtd_speedtest_init(void)
+{
+ int err, i;
+ long speed;
+ uint64_t tmp;
+
+ printk(KERN_INFO "\n");
+ printk(KERN_INFO "=================================================\n");
+ printk(PRINT_PREF "MTD device: %d\n", dev);
+
+ mtd = get_mtd_device(NULL, dev);
+ if (IS_ERR(mtd)) {
+ err = PTR_ERR(mtd);
+ printk(PRINT_PREF "error: cannot get MTD device\n");
+ return err;
+ }
+
+ if (mtd->writesize == 1) {
+ printk(PRINT_PREF "not NAND flash, assume page size is 512 "
+ "bytes.\n");
+ pgsize = 512;
+ } else
+ pgsize = mtd->writesize;
+
+ tmp = mtd->size;
+ do_div(tmp, mtd->erasesize);
+ ebcnt = tmp;
+ pgcnt = mtd->erasesize / mtd->writesize;
+
+ printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+ "page size %u, count of eraseblocks %u, pages per "
+ "eraseblock %u, OOB size %u\n",
+ (unsigned long long)mtd->size, mtd->erasesize,
+ pgsize, ebcnt, pgcnt, mtd->oobsize);
+
+ err = -ENOMEM;
+ iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
+ if (!iobuf) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out;
+ }
+
+ simple_srand(1);
+ set_random_data(iobuf, mtd->erasesize);
+
+ err = scan_for_bad_eraseblocks();
+ if (err)
+ goto out;
+
+ err = erase_whole_device();
+ if (err)
+ goto out;
+
+ /* Write all eraseblocks, 1 eraseblock at a time */
+ printk(PRINT_PREF "testing eraseblock write speed\n");
+ start_timing();
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = write_eraseblock(i);
+ if (err)
+ goto out;
+ cond_resched();
+ }
+ stop_timing();
+ speed = calc_speed();
+ printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed);
+
+ /* Read all eraseblocks, 1 eraseblock at a time */
+ printk(PRINT_PREF "testing eraseblock read speed\n");
+ start_timing();
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = read_eraseblock(i);
+ if (err)
+ goto out;
+ cond_resched();
+ }
+ stop_timing();
+ speed = calc_speed();
+ printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed);
+
+ err = erase_whole_device();
+ if (err)
+ goto out;
+
+ /* Write all eraseblocks, 1 page at a time */
+ printk(PRINT_PREF "testing page write speed\n");
+ start_timing();
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = write_eraseblock_by_page(i);
+ if (err)
+ goto out;
+ cond_resched();
+ }
+ stop_timing();
+ speed = calc_speed();
+ printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed);
+
+ /* Read all eraseblocks, 1 page at a time */
+ printk(PRINT_PREF "testing page read speed\n");
+ start_timing();
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = read_eraseblock_by_page(i);
+ if (err)
+ goto out;
+ cond_resched();
+ }
+ stop_timing();
+ speed = calc_speed();
+ printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed);
+
+ err = erase_whole_device();
+ if (err)
+ goto out;
+
+ /* Write all eraseblocks, 2 pages at a time */
+ printk(PRINT_PREF "testing 2 page write speed\n");
+ start_timing();
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = write_eraseblock_by_2pages(i);
+ if (err)
+ goto out;
+ cond_resched();
+ }
+ stop_timing();
+ speed = calc_speed();
+ printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed);
+
+ /* Read all eraseblocks, 2 pages at a time */
+ printk(PRINT_PREF "testing 2 page read speed\n");
+ start_timing();
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = read_eraseblock_by_2pages(i);
+ if (err)
+ goto out;
+ cond_resched();
+ }
+ stop_timing();
+ speed = calc_speed();
+ printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed);
+
+ /* Erase all eraseblocks */
+ printk(PRINT_PREF "Testing erase speed\n");
+ start_timing();
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = erase_eraseblock(i);
+ if (err)
+ goto out;
+ cond_resched();
+ }
+ stop_timing();
+ speed = calc_speed();
+ printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed);
+
+ printk(PRINT_PREF "finished\n");
+out:
+ kfree(iobuf);
+ kfree(bbt);
+ put_mtd_device(mtd);
+ if (err)
+ printk(PRINT_PREF "error %d occurred\n", err);
+ printk(KERN_INFO "=================================================\n");
+ return err;
+}
+module_init(mtd_speedtest_init);
+
+static void __exit mtd_speedtest_exit(void)
+{
+ return;
+}
+module_exit(mtd_speedtest_exit);
+
+MODULE_DESCRIPTION("Speed test module");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c
new file mode 100644
index 000000000000..63920476b57a
--- /dev/null
+++ b/drivers/mtd/tests/mtd_stresstest.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Test random reads, writes and erases on MTD device.
+ *
+ * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+
+#define PRINT_PREF KERN_INFO "mtd_stresstest: "
+
+static int dev;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static int count = 10000;
+module_param(count, int, S_IRUGO);
+MODULE_PARM_DESC(count, "Number of operations to do (default is 10000)");
+
+static struct mtd_info *mtd;
+static unsigned char *writebuf;
+static unsigned char *readbuf;
+static unsigned char *bbt;
+static int *offsets;
+
+static int pgsize;
+static int bufsize;
+static int ebcnt;
+static int pgcnt;
+static unsigned long next = 1;
+
+static inline unsigned int simple_rand(void)
+{
+ next = next * 1103515245 + 12345;
+ return (unsigned int)((next / 65536) % 32768);
+}
+
+static inline void simple_srand(unsigned long seed)
+{
+ next = seed;
+}
+
+static int rand_eb(void)
+{
+ int eb;
+
+again:
+ if (ebcnt < 32768)
+ eb = simple_rand();
+ else
+ eb = (simple_rand() << 15) | simple_rand();
+ /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */
+ eb %= (ebcnt - 1);
+ if (bbt[eb])
+ goto again;
+ return eb;
+}
+
+static int rand_offs(void)
+{
+ int offs;
+
+ if (bufsize < 32768)
+ offs = simple_rand();
+ else
+ offs = (simple_rand() << 15) | simple_rand();
+ offs %= bufsize;
+ return offs;
+}
+
+static int rand_len(int offs)
+{
+ int len;
+
+ if (bufsize < 32768)
+ len = simple_rand();
+ else
+ len = (simple_rand() << 15) | simple_rand();
+ len %= (bufsize - offs);
+ return len;
+}
+
+static int erase_eraseblock(int ebnum)
+{
+ int err;
+ struct erase_info ei;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ memset(&ei, 0, sizeof(struct erase_info));
+ ei.mtd = mtd;
+ ei.addr = addr;
+ ei.len = mtd->erasesize;
+
+ err = mtd->erase(mtd, &ei);
+ if (unlikely(err)) {
+ printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+ return err;
+ }
+
+ if (unlikely(ei.state == MTD_ERASE_FAILED)) {
+ printk(PRINT_PREF "some erase error occurred at EB %d\n",
+ ebnum);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int is_block_bad(int ebnum)
+{
+ loff_t addr = ebnum * mtd->erasesize;
+ int ret;
+
+ ret = mtd->block_isbad(mtd, addr);
+ if (ret)
+ printk(PRINT_PREF "block %d is bad\n", ebnum);
+ return ret;
+}
+
+static int do_read(void)
+{
+ size_t read = 0;
+ int eb = rand_eb();
+ int offs = rand_offs();
+ int len = rand_len(offs), err;
+ loff_t addr;
+
+ if (bbt[eb + 1]) {
+ if (offs >= mtd->erasesize)
+ offs -= mtd->erasesize;
+ if (offs + len > mtd->erasesize)
+ len = mtd->erasesize - offs;
+ }
+ addr = eb * mtd->erasesize + offs;
+ err = mtd->read(mtd, addr, len, &read, readbuf);
+ if (err == -EUCLEAN)
+ err = 0;
+ if (unlikely(err || read != len)) {
+ printk(PRINT_PREF "error: read failed at 0x%llx\n",
+ (long long)addr);
+ if (!err)
+ err = -EINVAL;
+ return err;
+ }
+ return 0;
+}
+
+static int do_write(void)
+{
+ int eb = rand_eb(), offs, err, len;
+ size_t written = 0;
+ loff_t addr;
+
+ offs = offsets[eb];
+ if (offs >= mtd->erasesize) {
+ err = erase_eraseblock(eb);
+ if (err)
+ return err;
+ offs = offsets[eb] = 0;
+ }
+ len = rand_len(offs);
+ len = ((len + pgsize - 1) / pgsize) * pgsize;
+ if (offs + len > mtd->erasesize) {
+ if (bbt[eb + 1])
+ len = mtd->erasesize - offs;
+ else {
+ err = erase_eraseblock(eb + 1);
+ if (err)
+ return err;
+ offsets[eb + 1] = 0;
+ }
+ }
+ addr = eb * mtd->erasesize + offs;
+ err = mtd->write(mtd, addr, len, &written, writebuf);
+ if (unlikely(err || written != len)) {
+ printk(PRINT_PREF "error: write failed at 0x%llx\n",
+ (long long)addr);
+ if (!err)
+ err = -EINVAL;
+ return err;
+ }
+ offs += len;
+ while (offs > mtd->erasesize) {
+ offsets[eb++] = mtd->erasesize;
+ offs -= mtd->erasesize;
+ }
+ offsets[eb] = offs;
+ return 0;
+}
+
+static int do_operation(void)
+{
+ if (simple_rand() & 1)
+ return do_read();
+ else
+ return do_write();
+}
+
+static int scan_for_bad_eraseblocks(void)
+{
+ int i, bad = 0;
+
+ bbt = kmalloc(ebcnt, GFP_KERNEL);
+ if (!bbt) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ return -ENOMEM;
+ }
+ memset(bbt, 0 , ebcnt);
+
+ printk(PRINT_PREF "scanning for bad eraseblocks\n");
+ for (i = 0; i < ebcnt; ++i) {
+ bbt[i] = is_block_bad(i) ? 1 : 0;
+ if (bbt[i])
+ bad += 1;
+ cond_resched();
+ }
+ printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+ return 0;
+}
+
+static int __init mtd_stresstest_init(void)
+{
+ int err;
+ int i, op;
+ uint64_t tmp;
+
+ printk(KERN_INFO "\n");
+ printk(KERN_INFO "=================================================\n");
+ printk(PRINT_PREF "MTD device: %d\n", dev);
+
+ mtd = get_mtd_device(NULL, dev);
+ if (IS_ERR(mtd)) {
+ err = PTR_ERR(mtd);
+ printk(PRINT_PREF "error: cannot get MTD device\n");
+ return err;
+ }
+
+ if (mtd->writesize == 1) {
+ printk(PRINT_PREF "not NAND flash, assume page size is 512 "
+ "bytes.\n");
+ pgsize = 512;
+ } else
+ pgsize = mtd->writesize;
+
+ tmp = mtd->size;
+ do_div(tmp, mtd->erasesize);
+ ebcnt = tmp;
+ pgcnt = mtd->erasesize / mtd->writesize;
+
+ printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+ "page size %u, count of eraseblocks %u, pages per "
+ "eraseblock %u, OOB size %u\n",
+ (unsigned long long)mtd->size, mtd->erasesize,
+ pgsize, ebcnt, pgcnt, mtd->oobsize);
+
+ /* Read or write up 2 eraseblocks at a time */
+ bufsize = mtd->erasesize * 2;
+
+ err = -ENOMEM;
+ readbuf = vmalloc(bufsize);
+ writebuf = vmalloc(bufsize);
+ offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL);
+ if (!readbuf || !writebuf || !offsets) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out;
+ }
+ for (i = 0; i < ebcnt; i++)
+ offsets[i] = mtd->erasesize;
+ simple_srand(current->pid);
+ for (i = 0; i < bufsize; i++)
+ writebuf[i] = simple_rand();
+
+ err = scan_for_bad_eraseblocks();
+ if (err)
+ goto out;
+
+ /* Do operations */
+ printk(PRINT_PREF "doing operations\n");
+ for (op = 0; op < count; op++) {
+ if ((op & 1023) == 0)
+ printk(PRINT_PREF "%d operations done\n", op);
+ err = do_operation();
+ if (err)
+ goto out;
+ cond_resched();
+ }
+ printk(PRINT_PREF "finished, %d operations done\n", op);
+
+out:
+ kfree(offsets);
+ kfree(bbt);
+ vfree(writebuf);
+ vfree(readbuf);
+ put_mtd_device(mtd);
+ if (err)
+ printk(PRINT_PREF "error %d occurred\n", err);
+ printk(KERN_INFO "=================================================\n");
+ return err;
+}
+module_init(mtd_stresstest_init);
+
+static void __exit mtd_stresstest_exit(void)
+{
+ return;
+}
+module_exit(mtd_stresstest_exit);
+
+MODULE_DESCRIPTION("Stress test module");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c
new file mode 100644
index 000000000000..5b889724268e
--- /dev/null
+++ b/drivers/mtd/tests/mtd_subpagetest.c
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Test sub-page read and write on MTD device.
+ * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/sched.h>
+
+#define PRINT_PREF KERN_INFO "mtd_subpagetest: "
+
+static int dev;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static struct mtd_info *mtd;
+static unsigned char *writebuf;
+static unsigned char *readbuf;
+static unsigned char *bbt;
+
+static int subpgsize;
+static int bufsize;
+static int ebcnt;
+static int pgcnt;
+static int errcnt;
+static unsigned long next = 1;
+
+static inline unsigned int simple_rand(void)
+{
+ next = next * 1103515245 + 12345;
+ return (unsigned int)((next / 65536) % 32768);
+}
+
+static inline void simple_srand(unsigned long seed)
+{
+ next = seed;
+}
+
+static void set_random_data(unsigned char *buf, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; ++i)
+ buf[i] = simple_rand();
+}
+
+static inline void clear_data(unsigned char *buf, size_t len)
+{
+ memset(buf, 0, len);
+}
+
+static int erase_eraseblock(int ebnum)
+{
+ int err;
+ struct erase_info ei;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ memset(&ei, 0, sizeof(struct erase_info));
+ ei.mtd = mtd;
+ ei.addr = addr;
+ ei.len = mtd->erasesize;
+
+ err = mtd->erase(mtd, &ei);
+ if (err) {
+ printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+ return err;
+ }
+
+ if (ei.state == MTD_ERASE_FAILED) {
+ printk(PRINT_PREF "some erase error occurred at EB %d\n",
+ ebnum);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int erase_whole_device(void)
+{
+ int err;
+ unsigned int i;
+
+ printk(PRINT_PREF "erasing whole device\n");
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = erase_eraseblock(i);
+ if (err)
+ return err;
+ cond_resched();
+ }
+ printk(PRINT_PREF "erased %u eraseblocks\n", i);
+ return 0;
+}
+
+static int write_eraseblock(int ebnum)
+{
+ size_t written = 0;
+ int err = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ set_random_data(writebuf, subpgsize);
+ err = mtd->write(mtd, addr, subpgsize, &written, writebuf);
+ if (unlikely(err || written != subpgsize)) {
+ printk(PRINT_PREF "error: write failed at %#llx\n",
+ (long long)addr);
+ if (written != subpgsize) {
+ printk(PRINT_PREF " write size: %#x\n", subpgsize);
+ printk(PRINT_PREF " written: %#zx\n", written);
+ }
+ return err ? err : -1;
+ }
+
+ addr += subpgsize;
+
+ set_random_data(writebuf, subpgsize);
+ err = mtd->write(mtd, addr, subpgsize, &written, writebuf);
+ if (unlikely(err || written != subpgsize)) {
+ printk(PRINT_PREF "error: write failed at %#llx\n",
+ (long long)addr);
+ if (written != subpgsize) {
+ printk(PRINT_PREF " write size: %#x\n", subpgsize);
+ printk(PRINT_PREF " written: %#zx\n", written);
+ }
+ return err ? err : -1;
+ }
+
+ return err;
+}
+
+static int write_eraseblock2(int ebnum)
+{
+ size_t written = 0;
+ int err = 0, k;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ for (k = 1; k < 33; ++k) {
+ if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
+ break;
+ set_random_data(writebuf, subpgsize * k);
+ err = mtd->write(mtd, addr, subpgsize * k, &written, writebuf);
+ if (unlikely(err || written != subpgsize * k)) {
+ printk(PRINT_PREF "error: write failed at %#llx\n",
+ (long long)addr);
+ if (written != subpgsize) {
+ printk(PRINT_PREF " write size: %#x\n",
+ subpgsize * k);
+ printk(PRINT_PREF " written: %#08zx\n",
+ written);
+ }
+ return err ? err : -1;
+ }
+ addr += subpgsize * k;
+ }
+
+ return err;
+}
+
+static void print_subpage(unsigned char *p)
+{
+ int i, j;
+
+ for (i = 0; i < subpgsize; ) {
+ for (j = 0; i < subpgsize && j < 32; ++i, ++j)
+ printk("%02x", *p++);
+ printk("\n");
+ }
+}
+
+static int verify_eraseblock(int ebnum)
+{
+ size_t read = 0;
+ int err = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ set_random_data(writebuf, subpgsize);
+ clear_data(readbuf, subpgsize);
+ read = 0;
+ err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
+ if (unlikely(err || read != subpgsize)) {
+ if (err == -EUCLEAN && read == subpgsize) {
+ printk(PRINT_PREF "ECC correction at %#llx\n",
+ (long long)addr);
+ err = 0;
+ } else {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr);
+ return err ? err : -1;
+ }
+ }
+ if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
+ printk(PRINT_PREF "error: verify failed at %#llx\n",
+ (long long)addr);
+ printk(PRINT_PREF "------------- written----------------\n");
+ print_subpage(writebuf);
+ printk(PRINT_PREF "------------- read ------------------\n");
+ print_subpage(readbuf);
+ printk(PRINT_PREF "-------------------------------------\n");
+ errcnt += 1;
+ }
+
+ addr += subpgsize;
+
+ set_random_data(writebuf, subpgsize);
+ clear_data(readbuf, subpgsize);
+ read = 0;
+ err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
+ if (unlikely(err || read != subpgsize)) {
+ if (err == -EUCLEAN && read == subpgsize) {
+ printk(PRINT_PREF "ECC correction at %#llx\n",
+ (long long)addr);
+ err = 0;
+ } else {
+ printk(PRINT_PREF "error: read failed at %#llx\n",
+ (long long)addr);
+ return err ? err : -1;
+ }
+ }
+ if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
+ printk(PRINT_PREF "error: verify failed at %#llx\n",
+ (long long)addr);
+ printk(PRINT_PREF "------------- written----------------\n");
+ print_subpage(writebuf);
+ printk(PRINT_PREF "------------- read ------------------\n");
+ print_subpage(readbuf);
+ printk(PRINT_PREF "-------------------------------------\n");
+ errcnt += 1;
+ }
+
+ return err;
+}
+
+static int verify_eraseblock2(int ebnum)
+{
+ size_t read = 0;
+ int err = 0, k;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ for (k = 1; k < 33; ++k) {
+ if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
+ break;
+ set_random_data(writebuf, subpgsize * k);
+ clear_data(readbuf, subpgsize * k);
+ read = 0;
+ err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf);
+ if (unlikely(err || read != subpgsize * k)) {
+ if (err == -EUCLEAN && read == subpgsize * k) {
+ printk(PRINT_PREF "ECC correction at %#llx\n",
+ (long long)addr);
+ err = 0;
+ } else {
+ printk(PRINT_PREF "error: read failed at "
+ "%#llx\n", (long long)addr);
+ return err ? err : -1;
+ }
+ }
+ if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
+ printk(PRINT_PREF "error: verify failed at %#llx\n",
+ (long long)addr);
+ errcnt += 1;
+ }
+ addr += subpgsize * k;
+ }
+
+ return err;
+}
+
+static int verify_eraseblock_ff(int ebnum)
+{
+ uint32_t j;
+ size_t read = 0;
+ int err = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ memset(writebuf, 0xff, subpgsize);
+ for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
+ clear_data(readbuf, subpgsize);
+ read = 0;
+ err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
+ if (unlikely(err || read != subpgsize)) {
+ if (err == -EUCLEAN && read == subpgsize) {
+ printk(PRINT_PREF "ECC correction at %#llx\n",
+ (long long)addr);
+ err = 0;
+ } else {
+ printk(PRINT_PREF "error: read failed at "
+ "%#llx\n", (long long)addr);
+ return err ? err : -1;
+ }
+ }
+ if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
+ printk(PRINT_PREF "error: verify 0xff failed at "
+ "%#llx\n", (long long)addr);
+ errcnt += 1;
+ }
+ addr += subpgsize;
+ }
+
+ return err;
+}
+
+static int verify_all_eraseblocks_ff(void)
+{
+ int err;
+ unsigned int i;
+
+ printk(PRINT_PREF "verifying all eraseblocks for 0xff\n");
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = verify_eraseblock_ff(i);
+ if (err)
+ return err;
+ if (i % 256 == 0)
+ printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+ cond_resched();
+ }
+ printk(PRINT_PREF "verified %u eraseblocks\n", i);
+ return 0;
+}
+
+static int is_block_bad(int ebnum)
+{
+ loff_t addr = ebnum * mtd->erasesize;
+ int ret;
+
+ ret = mtd->block_isbad(mtd, addr);
+ if (ret)
+ printk(PRINT_PREF "block %d is bad\n", ebnum);
+ return ret;
+}
+
+static int scan_for_bad_eraseblocks(void)
+{
+ int i, bad = 0;
+
+ bbt = kmalloc(ebcnt, GFP_KERNEL);
+ if (!bbt) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ return -ENOMEM;
+ }
+ memset(bbt, 0 , ebcnt);
+
+ printk(PRINT_PREF "scanning for bad eraseblocks\n");
+ for (i = 0; i < ebcnt; ++i) {
+ bbt[i] = is_block_bad(i) ? 1 : 0;
+ if (bbt[i])
+ bad += 1;
+ cond_resched();
+ }
+ printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
+ return 0;
+}
+
+static int __init mtd_subpagetest_init(void)
+{
+ int err = 0;
+ uint32_t i;
+ uint64_t tmp;
+
+ printk(KERN_INFO "\n");
+ printk(KERN_INFO "=================================================\n");
+ printk(PRINT_PREF "MTD device: %d\n", dev);
+
+ mtd = get_mtd_device(NULL, dev);
+ if (IS_ERR(mtd)) {
+ err = PTR_ERR(mtd);
+ printk(PRINT_PREF "error: cannot get MTD device\n");
+ return err;
+ }
+
+ if (mtd->type != MTD_NANDFLASH) {
+ printk(PRINT_PREF "this test requires NAND flash\n");
+ goto out;
+ }
+
+ subpgsize = mtd->writesize >> mtd->subpage_sft;
+ printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
+ "page size %u, subpage size %u, count of eraseblocks %u, "
+ "pages per eraseblock %u, OOB size %u\n",
+ (unsigned long long)mtd->size, mtd->erasesize,
+ mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
+
+ err = -ENOMEM;
+ bufsize = subpgsize * 32;
+ writebuf = kmalloc(bufsize, GFP_KERNEL);
+ if (!writebuf) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out;
+ }
+ readbuf = kmalloc(bufsize, GFP_KERNEL);
+ if (!readbuf) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out;
+ }
+
+ tmp = mtd->size;
+ do_div(tmp, mtd->erasesize);
+ ebcnt = tmp;
+ pgcnt = mtd->erasesize / mtd->writesize;
+
+ err = scan_for_bad_eraseblocks();
+ if (err)
+ goto out;
+
+ err = erase_whole_device();
+ if (err)
+ goto out;
+
+ printk(PRINT_PREF "writing whole device\n");
+ simple_srand(1);
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = write_eraseblock(i);
+ if (unlikely(err))
+ goto out;
+ if (i % 256 == 0)
+ printk(PRINT_PREF "written up to eraseblock %u\n", i);
+ cond_resched();
+ }
+ printk(PRINT_PREF "written %u eraseblocks\n", i);
+
+ simple_srand(1);
+ printk(PRINT_PREF "verifying all eraseblocks\n");
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = verify_eraseblock(i);
+ if (unlikely(err))
+ goto out;
+ if (i % 256 == 0)
+ printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+ cond_resched();
+ }
+ printk(PRINT_PREF "verified %u eraseblocks\n", i);
+
+ err = erase_whole_device();
+ if (err)
+ goto out;
+
+ err = verify_all_eraseblocks_ff();
+ if (err)
+ goto out;
+
+ /* Write all eraseblocks */
+ simple_srand(3);
+ printk(PRINT_PREF "writing whole device\n");
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = write_eraseblock2(i);
+ if (unlikely(err))
+ goto out;
+ if (i % 256 == 0)
+ printk(PRINT_PREF "written up to eraseblock %u\n", i);
+ cond_resched();
+ }
+ printk(PRINT_PREF "written %u eraseblocks\n", i);
+
+ /* Check all eraseblocks */
+ simple_srand(3);
+ printk(PRINT_PREF "verifying all eraseblocks\n");
+ for (i = 0; i < ebcnt; ++i) {
+ if (bbt[i])
+ continue;
+ err = verify_eraseblock2(i);
+ if (unlikely(err))
+ goto out;
+ if (i % 256 == 0)
+ printk(PRINT_PREF "verified up to eraseblock %u\n", i);
+ cond_resched();
+ }
+ printk(PRINT_PREF "verified %u eraseblocks\n", i);
+
+ err = erase_whole_device();
+ if (err)
+ goto out;
+
+ err = verify_all_eraseblocks_ff();
+ if (err)
+ goto out;
+
+ printk(PRINT_PREF "finished with %d errors\n", errcnt);
+
+out:
+ kfree(bbt);
+ kfree(readbuf);
+ kfree(writebuf);
+ put_mtd_device(mtd);
+ if (err)
+ printk(PRINT_PREF "error %d occurred\n", err);
+ printk(KERN_INFO "=================================================\n");
+ return err;
+}
+module_init(mtd_subpagetest_init);
+
+static void __exit mtd_subpagetest_exit(void)
+{
+ return;
+}
+module_exit(mtd_subpagetest_exit);
+
+MODULE_DESCRIPTION("Subpage test module");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_torturetest.c b/drivers/mtd/tests/mtd_torturetest.c
new file mode 100644
index 000000000000..631a0ab3a33c
--- /dev/null
+++ b/drivers/mtd/tests/mtd_torturetest.c
@@ -0,0 +1,530 @@
+/*
+ * Copyright (C) 2006-2008 Artem Bityutskiy
+ * Copyright (C) 2006-2008 Jarkko Lavinen
+ * Copyright (C) 2006-2008 Adrian Hunter
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors: Artem Bityutskiy, Jarkko Lavinen, Adria Hunter
+ *
+ * WARNING: this test program may kill your flash and your device. Do not
+ * use it unless you know what you do. Authors are not responsible for any
+ * damage caused by this program.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/sched.h>
+
+#define PRINT_PREF KERN_INFO "mtd_torturetest: "
+#define RETRIES 3
+
+static int eb = 8;
+module_param(eb, int, S_IRUGO);
+MODULE_PARM_DESC(eb, "eraseblock number within the selected MTD device");
+
+static int ebcnt = 32;
+module_param(ebcnt, int, S_IRUGO);
+MODULE_PARM_DESC(ebcnt, "number of consecutive eraseblocks to torture");
+
+static int pgcnt;
+module_param(pgcnt, int, S_IRUGO);
+MODULE_PARM_DESC(pgcnt, "number of pages per eraseblock to torture (0 => all)");
+
+static int dev;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static int gran = 512;
+module_param(gran, int, S_IRUGO);
+MODULE_PARM_DESC(gran, "how often the status information should be printed");
+
+static int check = 1;
+module_param(check, int, S_IRUGO);
+MODULE_PARM_DESC(check, "if the written data should be checked");
+
+static unsigned int cycles_count;
+module_param(cycles_count, uint, S_IRUGO);
+MODULE_PARM_DESC(cycles_count, "how many erase cycles to do "
+ "(infinite by default)");
+
+static struct mtd_info *mtd;
+
+/* This buffer contains 0x555555...0xAAAAAA... pattern */
+static unsigned char *patt_5A5;
+/* This buffer contains 0xAAAAAA...0x555555... pattern */
+static unsigned char *patt_A5A;
+/* This buffer contains all 0xFF bytes */
+static unsigned char *patt_FF;
+/* This a temporary buffer is use when checking data */
+static unsigned char *check_buf;
+/* How many erase cycles were done */
+static unsigned int erase_cycles;
+
+static int pgsize;
+static struct timeval start, finish;
+
+static void report_corrupt(unsigned char *read, unsigned char *written);
+
+static inline void start_timing(void)
+{
+ do_gettimeofday(&start);
+}
+
+static inline void stop_timing(void)
+{
+ do_gettimeofday(&finish);
+}
+
+/*
+ * Erase eraseblock number @ebnum.
+ */
+static inline int erase_eraseblock(int ebnum)
+{
+ int err;
+ struct erase_info ei;
+ loff_t addr = ebnum * mtd->erasesize;
+
+ memset(&ei, 0, sizeof(struct erase_info));
+ ei.mtd = mtd;
+ ei.addr = addr;
+ ei.len = mtd->erasesize;
+
+ err = mtd->erase(mtd, &ei);
+ if (err) {
+ printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
+ return err;
+ }
+
+ if (ei.state == MTD_ERASE_FAILED) {
+ printk(PRINT_PREF "some erase error occurred at EB %d\n",
+ ebnum);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * Check that the contents of eraseblock number @enbum is equivalent to the
+ * @buf buffer.
+ */
+static inline int check_eraseblock(int ebnum, unsigned char *buf)
+{
+ int err, retries = 0;
+ size_t read = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+ size_t len = mtd->erasesize;
+
+ if (pgcnt) {
+ addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
+ len = pgcnt * pgsize;
+ }
+
+retry:
+ err = mtd->read(mtd, addr, len, &read, check_buf);
+ if (err == -EUCLEAN)
+ printk(PRINT_PREF "single bit flip occurred at EB %d "
+ "MTD reported that it was fixed.\n", ebnum);
+ else if (err) {
+ printk(PRINT_PREF "error %d while reading EB %d, "
+ "read %zd\n", err, ebnum, read);
+ return err;
+ }
+
+ if (read != len) {
+ printk(PRINT_PREF "failed to read %zd bytes from EB %d, "
+ "read only %zd, but no error reported\n",
+ len, ebnum, read);
+ return -EIO;
+ }
+
+ if (memcmp(buf, check_buf, len)) {
+ printk(PRINT_PREF "read wrong data from EB %d\n", ebnum);
+ report_corrupt(check_buf, buf);
+
+ if (retries++ < RETRIES) {
+ /* Try read again */
+ yield();
+ printk(PRINT_PREF "re-try reading data from EB %d\n",
+ ebnum);
+ goto retry;
+ } else {
+ printk(PRINT_PREF "retried %d times, still errors, "
+ "give-up\n", RETRIES);
+ return -EINVAL;
+ }
+ }
+
+ if (retries != 0)
+ printk(PRINT_PREF "only attempt number %d was OK (!!!)\n",
+ retries);
+
+ return 0;
+}
+
+static inline int write_pattern(int ebnum, void *buf)
+{
+ int err;
+ size_t written = 0;
+ loff_t addr = ebnum * mtd->erasesize;
+ size_t len = mtd->erasesize;
+
+ if (pgcnt) {
+ addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
+ len = pgcnt * pgsize;
+ }
+ err = mtd->write(mtd, addr, len, &written, buf);
+ if (err) {
+ printk(PRINT_PREF "error %d while writing EB %d, written %zd"
+ " bytes\n", err, ebnum, written);
+ return err;
+ }
+ if (written != len) {
+ printk(PRINT_PREF "written only %zd bytes of %zd, but no error"
+ " reported\n", written, len);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int __init tort_init(void)
+{
+ int err = 0, i, infinite = !cycles_count;
+ int bad_ebs[ebcnt];
+
+ printk(KERN_INFO "\n");
+ printk(KERN_INFO "=================================================\n");
+ printk(PRINT_PREF "Warning: this program is trying to wear out your "
+ "flash, stop it if this is not wanted.\n");
+ printk(PRINT_PREF "MTD device: %d\n", dev);
+ printk(PRINT_PREF "torture %d eraseblocks (%d-%d) of mtd%d\n",
+ ebcnt, eb, eb + ebcnt - 1, dev);
+ if (pgcnt)
+ printk(PRINT_PREF "torturing just %d pages per eraseblock\n",
+ pgcnt);
+ printk(PRINT_PREF "write verify %s\n", check ? "enabled" : "disabled");
+
+ mtd = get_mtd_device(NULL, dev);
+ if (IS_ERR(mtd)) {
+ err = PTR_ERR(mtd);
+ printk(PRINT_PREF "error: cannot get MTD device\n");
+ return err;
+ }
+
+ if (mtd->writesize == 1) {
+ printk(PRINT_PREF "not NAND flash, assume page size is 512 "
+ "bytes.\n");
+ pgsize = 512;
+ } else
+ pgsize = mtd->writesize;
+
+ if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) {
+ printk(PRINT_PREF "error: invalid pgcnt value %d\n", pgcnt);
+ goto out_mtd;
+ }
+
+ err = -ENOMEM;
+ patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL);
+ if (!patt_5A5) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out_mtd;
+ }
+
+ patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL);
+ if (!patt_A5A) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out_patt_5A5;
+ }
+
+ patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL);
+ if (!patt_FF) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out_patt_A5A;
+ }
+
+ check_buf = kmalloc(mtd->erasesize, GFP_KERNEL);
+ if (!check_buf) {
+ printk(PRINT_PREF "error: cannot allocate memory\n");
+ goto out_patt_FF;
+ }
+
+ err = 0;
+
+ /* Initialize patterns */
+ memset(patt_FF, 0xFF, mtd->erasesize);
+ for (i = 0; i < mtd->erasesize / pgsize; i++) {
+ if (!(i & 1)) {
+ memset(patt_5A5 + i * pgsize, 0x55, pgsize);
+ memset(patt_A5A + i * pgsize, 0xAA, pgsize);
+ } else {
+ memset(patt_5A5 + i * pgsize, 0xAA, pgsize);
+ memset(patt_A5A + i * pgsize, 0x55, pgsize);
+ }
+ }
+
+ /*
+ * Check if there is a bad eraseblock among those we are going to test.
+ */
+ memset(&bad_ebs[0], 0, sizeof(int) * ebcnt);
+ if (mtd->block_isbad) {
+ for (i = eb; i < eb + ebcnt; i++) {
+ err = mtd->block_isbad(mtd,
+ (loff_t)i * mtd->erasesize);
+
+ if (err < 0) {
+ printk(PRINT_PREF "block_isbad() returned %d "
+ "for EB %d\n", err, i);
+ goto out;
+ }
+
+ if (err) {
+ printk("EB %d is bad. Skip it.\n", i);
+ bad_ebs[i - eb] = 1;
+ }
+ }
+ }
+
+ start_timing();
+ while (1) {
+ int i;
+ void *patt;
+
+ /* Erase all eraseblocks */
+ for (i = eb; i < eb + ebcnt; i++) {
+ if (bad_ebs[i - eb])
+ continue;
+ err = erase_eraseblock(i);
+ if (err)
+ goto out;
+ cond_resched();
+ }
+
+ /* Check if the eraseblocks contain only 0xFF bytes */
+ if (check) {
+ for (i = eb; i < eb + ebcnt; i++) {
+ if (bad_ebs[i - eb])
+ continue;
+ err = check_eraseblock(i, patt_FF);
+ if (err) {
+ printk(PRINT_PREF "verify failed"
+ " for 0xFF... pattern\n");
+ goto out;
+ }
+ cond_resched();
+ }
+ }
+
+ /* Write the pattern */
+ for (i = eb; i < eb + ebcnt; i++) {
+ if (bad_ebs[i - eb])
+ continue;
+ if ((eb + erase_cycles) & 1)
+ patt = patt_5A5;
+ else
+ patt = patt_A5A;
+ err = write_pattern(i, patt);
+ if (err)
+ goto out;
+ cond_resched();
+ }
+
+ /* Verify what we wrote */
+ if (check) {
+ for (i = eb; i < eb + ebcnt; i++) {
+ if (bad_ebs[i - eb])
+ continue;
+ if ((eb + erase_cycles) & 1)
+ patt = patt_5A5;
+ else
+ patt = patt_A5A;
+ err = check_eraseblock(i, patt);
+ if (err) {
+ printk(PRINT_PREF "verify failed for %s"
+ " pattern\n",
+ ((eb + erase_cycles) & 1) ?
+ "0x55AA55..." : "0xAA55AA...");
+ goto out;
+ }
+ cond_resched();
+ }
+ }
+
+ erase_cycles += 1;
+
+ if (erase_cycles % gran == 0) {
+ long ms;
+
+ stop_timing();
+ ms = (finish.tv_sec - start.tv_sec) * 1000 +
+ (finish.tv_usec - start.tv_usec) / 1000;
+ printk(PRINT_PREF "%08u erase cycles done, took %lu "
+ "milliseconds (%lu seconds)\n",
+ erase_cycles, ms, ms / 1000);
+ start_timing();
+ }
+
+ if (!infinite && --cycles_count == 0)
+ break;
+ }
+out:
+
+ printk(PRINT_PREF "finished after %u erase cycles\n",
+ erase_cycles);
+ kfree(check_buf);
+out_patt_FF:
+ kfree(patt_FF);
+out_patt_A5A:
+ kfree(patt_A5A);
+out_patt_5A5:
+ kfree(patt_5A5);
+out_mtd:
+ put_mtd_device(mtd);
+ if (err)
+ printk(PRINT_PREF "error %d occurred during torturing\n", err);
+ printk(KERN_INFO "=================================================\n");
+ return err;
+}
+module_init(tort_init);
+
+static void __exit tort_exit(void)
+{
+ return;
+}
+module_exit(tort_exit);
+
+static int countdiffs(unsigned char *buf, unsigned char *check_buf,
+ unsigned offset, unsigned len, unsigned *bytesp,
+ unsigned *bitsp);
+static void print_bufs(unsigned char *read, unsigned char *written, int start,
+ int len);
+
+/*
+ * Report the detailed information about how the read EB differs from what was
+ * written.
+ */
+static void report_corrupt(unsigned char *read, unsigned char *written)
+{
+ int i;
+ int bytes, bits, pages, first;
+ int offset, len;
+ size_t check_len = mtd->erasesize;
+
+ if (pgcnt)
+ check_len = pgcnt * pgsize;
+
+ bytes = bits = pages = 0;
+ for (i = 0; i < check_len; i += pgsize)
+ if (countdiffs(written, read, i, pgsize, &bytes,
+ &bits) >= 0)
+ pages++;
+
+ printk(PRINT_PREF "verify fails on %d pages, %d bytes/%d bits\n",
+ pages, bytes, bits);
+ printk(PRINT_PREF "The following is a list of all differences between"
+ " what was read from flash and what was expected\n");
+
+ for (i = 0; i < check_len; i += pgsize) {
+ cond_resched();
+ bytes = bits = 0;
+ first = countdiffs(written, read, i, pgsize, &bytes,
+ &bits);
+ if (first < 0)
+ continue;
+
+ printk("-------------------------------------------------------"
+ "----------------------------------\n");
+
+ printk(PRINT_PREF "Page %zd has %d bytes/%d bits failing verify,"
+ " starting at offset 0x%x\n",
+ (mtd->erasesize - check_len + i) / pgsize,
+ bytes, bits, first);
+
+ offset = first & ~0x7;
+ len = ((first + bytes) | 0x7) + 1 - offset;
+
+ print_bufs(read, written, offset, len);
+ }
+}
+
+static void print_bufs(unsigned char *read, unsigned char *written, int start,
+ int len)
+{
+ int i = 0, j1, j2;
+ char *diff;
+
+ printk("Offset Read Written\n");
+ while (i < len) {
+ printk("0x%08x: ", start + i);
+ diff = " ";
+ for (j1 = 0; j1 < 8 && i + j1 < len; j1++) {
+ printk(" %02x", read[start + i + j1]);
+ if (read[start + i + j1] != written[start + i + j1])
+ diff = "***";
+ }
+
+ while (j1 < 8) {
+ printk(" ");
+ j1 += 1;
+ }
+
+ printk(" %s ", diff);
+
+ for (j2 = 0; j2 < 8 && i + j2 < len; j2++)
+ printk(" %02x", written[start + i + j2]);
+ printk("\n");
+ i += 8;
+ }
+}
+
+/*
+ * Count the number of differing bytes and bits and return the first differing
+ * offset.
+ */
+static int countdiffs(unsigned char *buf, unsigned char *check_buf,
+ unsigned offset, unsigned len, unsigned *bytesp,
+ unsigned *bitsp)
+{
+ unsigned i, bit;
+ int first = -1;
+
+ for (i = offset; i < offset + len; i++)
+ if (buf[i] != check_buf[i]) {
+ first = i;
+ break;
+ }
+
+ while (i < offset + len) {
+ if (buf[i] != check_buf[i]) {
+ (*bytesp)++;
+ bit = 1;
+ while (bit < 256) {
+ if ((buf[i] & bit) != (check_buf[i] & bit))
+ (*bitsp)++;
+ bit <<= 1;
+ }
+ }
+ i++;
+ }
+
+ return first;
+}
+
+MODULE_DESCRIPTION("Eraseblock torturing module");
+MODULE_AUTHOR("Artem Bityutskiy, Jarkko Lavinen, Adrian Hunter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 7caf22cd5ad0..9082768cc6c3 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -561,7 +561,7 @@ static int io_init(struct ubi_device *ubi)
*/
ubi->peb_size = ubi->mtd->erasesize;
- ubi->peb_count = ubi->mtd->size / ubi->mtd->erasesize;
+ ubi->peb_count = mtd_div_by_eb(ubi->mtd->size, ubi->mtd);
ubi->flash_size = ubi->mtd->size;
if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 048a606cebde..25def348e5ba 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -717,7 +717,7 @@ write_error:
* to the real data size, although the @buf buffer has to contain the
* alignment. In all other cases, @len has to be aligned.
*
- * It is prohibited to write more then once to logical eraseblocks of static
+ * It is prohibited to write more than once to logical eraseblocks of static
* volumes. This function returns zero in case of success and a negative error
* code in case of failure.
*/
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index 605812bb0b1a..6dd4f5e77f82 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -215,7 +215,8 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
struct ubi_volume *vol;
struct ubi_device *ubi;
- dbg_gen("erase %u bytes at offset %u", instr->len, instr->addr);
+ dbg_gen("erase %llu bytes at offset %llu", (unsigned long long)instr->len,
+ (unsigned long long)instr->addr);
if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize)
return -EINVAL;
@@ -223,11 +224,11 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
if (instr->len < 0 || instr->addr + instr->len > mtd->size)
return -EINVAL;
- if (instr->addr % mtd->writesize || instr->len % mtd->writesize)
+ if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd))
return -EINVAL;
- lnum = instr->addr / mtd->erasesize;
- count = instr->len / mtd->erasesize;
+ lnum = mtd_div_by_eb(instr->addr, mtd);
+ count = mtd_div_by_eb(instr->len, mtd);
vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
ubi = vol->ubi;
@@ -255,7 +256,7 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
out_err:
instr->state = MTD_ERASE_FAILED;
- instr->fail_addr = lnum * mtd->erasesize;
+ instr->fail_addr = (long long)lnum * mtd->erasesize;
return err;
}
@@ -294,7 +295,7 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
* bytes.
*/
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
- mtd->size = vol->usable_leb_size * vol->reserved_pebs;
+ mtd->size = (long long)vol->usable_leb_size * vol->reserved_pebs;
else
mtd->size = vol->used_bytes;
@@ -304,8 +305,8 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
return -ENFILE;
}
- dbg_gen("added mtd%d (\"%s\"), size %u, EB size %u",
- mtd->index, mtd->name, mtd->size, mtd->erasesize);
+ dbg_gen("added mtd%d (\"%s\"), size %llu, EB size %u",
+ mtd->index, mtd->name, (unsigned long long)mtd->size, mtd->erasesize);
return 0;
}
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index a74118c05745..fe81039f2a7c 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -465,7 +465,7 @@ out:
* This function synchronously erases physical eraseblock @pnum. If @torture
* flag is not zero, the physical eraseblock is checked by means of writing
* different patterns to it and reading them back. If the torturing is enabled,
- * the physical eraseblock is erased more then once.
+ * the physical eraseblock is erased more than once.
*
* This function returns the number of erasures made in case of success, %-EIO
* if the erasure failed or the torturing test failed, and other negative error
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 5d9bcf109c13..4abbe573fa40 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -564,7 +564,7 @@ EXPORT_SYMBOL_GPL(ubi_leb_unmap);
* @dtype: expected data type
*
* This function maps an un-mapped logical eraseblock @lnum to a physical
- * eraseblock. This means, that after a successfull invocation of this
+ * eraseblock. This means, that after a successful invocation of this
* function the logical eraseblock @lnum will be empty (contain only %0xFF
* bytes) and be mapped to a physical eraseblock, even if an unclean reboot
* happens.
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 41d47e1cf15c..ecde202a5a12 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -478,7 +478,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
return 0;
} else {
/*
- * This logical eraseblock is older then the one found
+ * This logical eraseblock is older than the one found
* previously.
*/
if (cmp_res & 4)
diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h
index 2ad940409053..8419fdccc79c 100644
--- a/drivers/mtd/ubi/ubi-media.h
+++ b/drivers/mtd/ubi/ubi-media.h
@@ -135,7 +135,7 @@ enum {
* The erase counter header takes 64 bytes and has a plenty of unused space for
* future usage. The unused fields are zeroed. The @version field is used to
* indicate the version of UBI implementation which is supposed to be able to
- * work with this UBI image. If @version is greater then the current UBI
+ * work with this UBI image. If @version is greater than the current UBI
* version, the image is rejected. This may be useful in future if something
* is changed radically. This field is duplicated in the volume identifier
* header.
@@ -187,7 +187,7 @@ struct ubi_ec_hdr {
* (sequence number) is used to distinguish between older and newer versions of
* logical eraseblocks.
*
- * There are 2 situations when there may be more then one physical eraseblock
+ * There are 2 situations when there may be more than one physical eraseblock
* corresponding to the same logical eraseblock, i.e., having the same @vol_id
* and @lnum values in the volume identifier header. Suppose we have a logical
* eraseblock L and it is mapped to the physical eraseblock P.
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index 333c8941552f..1afc61e7455d 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -577,7 +577,7 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) {
/* Auto re-size flag may be set only for one volume */
if (ubi->autoresize_vol_id != -1) {
- ubi_err("more then one auto-resize volume (%d "
+ ubi_err("more than one auto-resize volume (%d "
"and %d)", ubi->autoresize_vol_id, i);
kfree(vol);
return -EINVAL;
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 14901cb82c18..891534f8210d 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -128,7 +128,7 @@
* situation when the picked physical eraseblock is constantly erased after the
* data is written to it. So, we have a constant which limits the highest erase
* counter of the free physical eraseblock to pick. Namely, the WL sub-system
- * does not pick eraseblocks with erase counter greater then the lowest erase
+ * does not pick eraseblocks with erase counter greater than the lowest erase
* counter plus %WL_FREE_MAX_DIFF.
*/
#define WL_FREE_MAX_DIFF (2*UBI_WL_THRESHOLD)
@@ -917,7 +917,7 @@ static int ensure_wear_leveling(struct ubi_device *ubi)
/*
* We schedule wear-leveling only if the difference between the
* lowest erase counter of used physical eraseblocks and a high
- * erase counter of free physical eraseblocks is greater then
+ * erase counter of free physical eraseblocks is greater than
* %UBI_WL_THRESHOLD.
*/
e1 = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, u.rb);
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index c092c3929224..5b91a85fe107 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -177,6 +177,7 @@ static const struct net_device_ops el2_netdev_ops = {
.ndo_get_stats = eip_get_stats,
.ndo_set_multicast_list = eip_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = eip_poll,
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 665e7fdf27a1..cdbbb6226fc5 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -3109,6 +3109,8 @@ static void acpi_set_WOL(struct net_device *dev)
struct vortex_private *vp = netdev_priv(dev);
void __iomem *ioaddr = vp->ioaddr;
+ device_set_wakeup_enable(vp->gendev, vp->enable_wol);
+
if (vp->enable_wol) {
/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
EL3WINDOW(7);
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index dd7ac8290aec..4e19ae3ce6be 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -1821,6 +1821,7 @@ static const struct net_device_ops cp_netdev_ops = {
.ndo_open = cp_open,
.ndo_stop = cp_close,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_set_multicast_list = cp_set_rx_mode,
.ndo_get_stats = cp_get_stats,
.ndo_do_ioctl = cp_ioctl,
@@ -1832,6 +1833,7 @@ static const struct net_device_ops cp_netdev_ops = {
#ifdef BROKEN
.ndo_change_mtu = cp_change_mtu,
#endif
+
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = cp_poll_controller,
#endif
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index fe370f805793..a5b24202d564 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -917,6 +917,7 @@ static const struct net_device_ops rtl8139_netdev_ops = {
.ndo_stop = rtl8139_close,
.ndo_get_stats = rtl8139_get_stats,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_start_xmit = rtl8139_start_xmit,
.ndo_set_multicast_list = rtl8139_set_rx_mode,
.ndo_do_ioctl = netdev_ioctl,
@@ -924,7 +925,6 @@ static const struct net_device_ops rtl8139_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = rtl8139_poll_controller,
#endif
-
};
static int __devinit rtl8139_init_one (struct pci_dev *pdev,
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index fbe609a51e02..ec3e22e6306f 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -63,6 +63,7 @@ const struct net_device_ops ei_netdev_ops = {
.ndo_get_stats = ei_get_stats,
.ndo_set_multicast_list = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ei_poll,
diff --git a/drivers/net/8390p.c b/drivers/net/8390p.c
index ee70b358a816..da863c91d1d0 100644
--- a/drivers/net/8390p.c
+++ b/drivers/net/8390p.c
@@ -68,6 +68,7 @@ const struct net_device_ops eip_netdev_ops = {
.ndo_get_stats = eip_get_stats,
.ndo_set_multicast_list = eip_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = eip_poll,
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 9a18270c1081..9fe8cb7d43ac 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -830,7 +830,7 @@ config ULTRA32
config BFIN_MAC
tristate "Blackfin on-chip MAC support"
- depends on NET_ETHERNET && (BF526 || BF527 || BF536 || BF537)
+ depends on NET_ETHERNET && (BF516 || BF518 || BF526 || BF527 || BF536 || BF537)
select CRC32
select MII
select PHYLIB
@@ -1600,7 +1600,7 @@ config 8139_OLD_RX_RESET
old RX-reset behavior. If unsure, say N.
config R6040
- tristate "RDC R6040 Fast Ethernet Adapter support (EXPERIMENTAL)"
+ tristate "RDC R6040 Fast Ethernet Adapter support"
depends on NET_PCI && PCI
select CRC32
select MII
@@ -2614,6 +2614,8 @@ source "drivers/net/tokenring/Kconfig"
source "drivers/net/wireless/Kconfig"
+source "drivers/net/wimax/Kconfig"
+
source "drivers/net/usb/Kconfig"
source "drivers/net/pcmcia/Kconfig"
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e5c34b464211..a3c5c002f224 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -263,3 +263,4 @@ obj-$(CONFIG_NIU) += niu.o
obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
obj-$(CONFIG_SFC) += sfc/
+obj-$(CONFIG_WIMAX) += wimax/
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 5b396ff6c83f..9589d620639d 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -460,6 +460,7 @@ static const struct net_device_ops ace_netdev_ops = {
.ndo_get_stats = ace_get_stats,
.ndo_start_xmit = ace_start_xmit,
.ndo_set_multicast_list = ace_set_multicast_list,
+ .ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = ace_set_mac_addr,
.ndo_change_mtu = ace_change_mtu,
#if ACENIC_DO_VLAN
diff --git a/drivers/net/acenic_firmware.h b/drivers/net/acenic_firmware.h
deleted file mode 100644
index fd41f7887e27..000000000000
--- a/drivers/net/acenic_firmware.h
+++ /dev/null
@@ -1,9456 +0,0 @@
-/*
- * Declare these here even if Tigon I support is disabled to avoid
- * the compiler complaining about undefined symbols.
- */
-#define tigonFwReleaseMajor 0xc
-#define tigonFwReleaseMinor 0x4
-#define tigonFwReleaseFix 0xb
-#define tigonFwStartAddr 0x00004000
-#define tigonFwTextAddr 0x00004000
-#define tigonFwTextLen 0x11140
-#define tigonFwRodataAddr 0x00015140
-#define tigonFwRodataLen 0xac0
-#define tigonFwDataAddr 0x00015c20
-#define tigonFwDataLen 0x170
-#define tigonFwSbssAddr 0x00015d90
-#define tigonFwSbssLen 0x38
-#define tigonFwBssAddr 0x00015dd0
-#define tigonFwBssLen 0x2080
-#ifdef CONFIG_ACENIC_OMIT_TIGON_I
-#define tigonFwText NULL
-#define tigonFwData NULL
-#define tigonFwRodata NULL
-#else
-/* Generated by genfw.c */
-static u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = {
-0x10000003,
-0x0, 0xd, 0xd, 0x3c1d0001,
-0x8fbd5c54, 0x3a0f021, 0x3c100000, 0x26104000,
-0xc00100c, 0x0, 0xd, 0x27bdffd8,
-0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021,
-0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8,
-0xafbf0024, 0xc002488, 0xafb00020, 0xc0023e8,
-0x0, 0x3c040001, 0x248451a4, 0x24050001,
-0x2e03021, 0x3821, 0x3c100001, 0x26107e50,
-0xafb00010, 0xc002403, 0xafbb0014, 0x3c02000f,
-0x3442ffff, 0x2021024, 0x362102b, 0x10400009,
-0x24050003, 0x3c040001, 0x248451b0, 0x2003021,
-0x3603821, 0x3c020010, 0xafa20010, 0xc002403,
-0xafa00014, 0x2021, 0x3405c000, 0x3c010001,
-0x370821, 0xa02083b0, 0x3c010001, 0x370821,
-0xa02083b2, 0x3c010001, 0x370821, 0xa02083b3,
-0x3c010001, 0x370821, 0xac2083b4, 0xa2e004d8,
-0x418c0, 0x24840001, 0x771021, 0xac40727c,
-0x771021, 0xac407280, 0x2e31021, 0xa445727c,
-0x2c820020, 0x1440fff7, 0x418c0, 0x2021,
-0x3405c000, 0x418c0, 0x24840001, 0x771021,
-0xac40737c, 0x771021, 0xac407380, 0x2e31021,
-0xa445737c, 0x2c820080, 0x5440fff7, 0x418c0,
-0xaf800054, 0xaf80011c, 0x8f820044, 0x34420040,
-0xaf820044, 0x8f820044, 0x34420020, 0xaf820044,
-0x8f420218, 0x30420002, 0x10400009, 0x0,
-0x8f420220, 0x3c030002, 0x34630004, 0x431025,
-0xaee204c4, 0x8f42021c, 0x8001074, 0x34420004,
-0x8f420220, 0x3c030002, 0x34630006, 0x431025,
-0xaee204c4, 0x8f42021c, 0x34420006, 0xaee204cc,
-0x8f420218, 0x30420010, 0x1040000a, 0x0,
-0x8f42021c, 0x34420004, 0xaee204c8, 0x8f420220,
-0x3c03000a, 0x34630004, 0x431025, 0x800108a,
-0xaee204c0, 0x8f420220, 0x3c03000a, 0x34630006,
-0x431025, 0xaee204c0, 0x8f42021c, 0x34420006,
-0xaee204c8, 0x8f420218, 0x30420200, 0x10400003,
-0x24020001, 0x8001091, 0xa2e27248, 0xa2e07248,
-0x24020001, 0xaf8200a0, 0xaf8200b0, 0x8f830054,
-0x8f820054, 0x8001099, 0x24630064, 0x8f820054,
-0x621023, 0x2c420065, 0x1440fffc, 0x0,
-0xaf800044, 0x8f420208, 0x8f43020c, 0xaee20010,
-0xaee30014, 0x8ee40010, 0x8ee50014, 0x26e20030,
-0xaee20028, 0x24020490, 0xaee20018, 0xaf840090,
-0xaf850094, 0x8ee20028, 0xaf8200b4, 0x96e2001a,
-0xaf82009c, 0x8f8200b0, 0x8ee304cc, 0x431025,
-0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd,
-0x0, 0x8ee20450, 0x8ee30454, 0xaee304fc,
-0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d,
-0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001,
-0x248451bc, 0x3c050001, 0xafa00010, 0xafa00014,
-0x8ee704fc, 0x34a5f000, 0xc002403, 0x603021,
-0x26e40030, 0xc002488, 0x24050400, 0x27440080,
-0xc002488, 0x24050080, 0x26e4777c, 0xc002488,
-0x24050400, 0x8f42025c, 0x26e40094, 0xaee20060,
-0x8f420260, 0x27450200, 0x24060008, 0xaee20068,
-0x24020006, 0xc00249a, 0xaee20064, 0x3c023b9a,
-0x3442ca00, 0x2021, 0x24030002, 0xaee30074,
-0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104,
-0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001,
-0x641821, 0x90635c20, 0x2e41021, 0x24840001,
-0xa043009c, 0x2c82000f, 0x1440fff8, 0x0,
-0x8f820040, 0x2e41821, 0x24840001, 0x21702,
-0x24420030, 0xa062009c, 0x2e41021, 0xa040009c,
-0x96e2046a, 0x30420003, 0x14400009, 0x0,
-0x96e2047a, 0x30420003, 0x50400131, 0x3c030800,
-0x96e2046a, 0x30420003, 0x1040002a, 0x3c020700,
-0x96e2047a, 0x30420003, 0x10400026, 0x3c020700,
-0x96e3047a, 0x96e2046a, 0x14620022, 0x3c020700,
-0x8ee204c0, 0x24030001, 0xa2e34e20, 0x34420e00,
-0xaee204c0, 0x8f420218, 0x30420100, 0x10400005,
-0x0, 0x3c020001, 0x2442e168, 0x800111d,
-0x21100, 0x3c020001, 0x2442d35c, 0x21100,
-0x21182, 0x3c030800, 0x431025, 0x3c010001,
-0xac221238, 0x3c020001, 0x2442f680, 0x21100,
-0x21182, 0x3c030800, 0x431025, 0x3c010001,
-0xac221278, 0x8ee20000, 0x34424000, 0x8001238,
-0xaee20000, 0x34423000, 0xafa20018, 0x8ee20608,
-0x8f430228, 0x24420001, 0x304900ff, 0x512300e2,
-0xafa00010, 0x8ee20608, 0x210c0, 0x571021,
-0x8fa30018, 0x8fa4001c, 0xac43060c, 0xac440610,
-0x8f870120, 0x27623800, 0x24e80020, 0x102102b,
-0x50400001, 0x27683000, 0x8f820128, 0x11020004,
-0x0, 0x8f820124, 0x15020007, 0x1021,
-0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4,
-0x80011a0, 0x8ee201a4, 0x8ee40608, 0x420c0,
-0x801821, 0x8ee40430, 0x8ee50434, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0xace40000,
-0xace50004, 0x8ee30608, 0x24020008, 0xa4e2000e,
-0x2402000d, 0xace20018, 0xace9001c, 0x318c0,
-0x2463060c, 0x2e31021, 0xace20008, 0x8ee204c4,
-0xace20010, 0xaf880120, 0x92e24e20, 0x14400037,
-0x24060001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
-0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
-0x0, 0x800118a, 0x0, 0x14a00005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
-0xac800000, 0x80011a0, 0x0, 0x8ee24e30,
-0x24030040, 0x24420001, 0x50430003, 0x1021,
-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x24020007,
-0xac820000, 0x24020001, 0xac820004, 0x54c0000c,
-0xaee90608, 0x3c040001, 0x248451c8, 0xafa00010,
-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
-0xc002403, 0x34a5f000, 0x8001223, 0x0,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4,
-0x8001207, 0x8ee201a4, 0x8ee20608, 0xac62001c,
-0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400037, 0x24060001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c830000, 0x24020012, 0x1462001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee54e30, 0x24420001, 0x10430007, 0x0,
-0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
-0x80011f1, 0x0, 0x14a00005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x8001207, 0x0, 0x8ee24e30, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020012, 0xac820000,
-0x24020001, 0xac820004, 0x14c0001b, 0x0,
-0x3c040001, 0x248451d0, 0xafa00010, 0xafa00014,
-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
-0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0,
-0x8001223, 0x8ee201b0, 0x3c040001, 0x248451dc,
-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
-0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001,
-0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001,
-0x248451e8, 0x3405f001, 0x24420001, 0xaee20160,
-0x8ee20160, 0x3021, 0x3821, 0xafa00010,
-0xc002403, 0xafa00014, 0x8001238, 0x0,
-0x3c020001, 0x2442f5a8, 0x21100, 0x21182,
-0x431025, 0x3c010001, 0xac221278, 0x96e2045a,
-0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8,
-0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8,
-0x3c040001, 0x248451f4, 0x24020001, 0xa2e204ec,
-0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001,
-0x2442a390, 0x451024, 0x21082, 0xaee304c8,
-0x3c030800, 0x431025, 0x3c010001, 0xac221220,
-0x3c020001, 0x2442add4, 0x451024, 0x21082,
-0x431025, 0x3c010001, 0xac221280, 0x96e6045a,
-0x3821, 0x24050011, 0xafa00010, 0xc002403,
-0xafa00014, 0x8001268, 0x0, 0x3c020001,
-0x2442a9d4, 0x21100, 0x21182, 0x3c030800,
-0x431025, 0x3c010001, 0xac221280, 0x96e2046a,
-0x30420010, 0x14400009, 0x0, 0x96e2047a,
-0x30420010, 0x10400112, 0x0, 0x96e2046a,
-0x30420010, 0x10400005, 0x3c020700, 0x96e2047a,
-0x30420010, 0x14400102, 0x3c020700, 0x34423000,
-0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
-0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608,
-0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
-0xac43060c, 0xac440610, 0x8f870120, 0x27623800,
-0x24e80020, 0x102102b, 0x50400001, 0x27683000,
-0x8f820128, 0x11020004, 0x0, 0x8f820124,
-0x15020007, 0x1021, 0x8ee201a4, 0x3021,
-0x24420001, 0xaee201a4, 0x80012ea, 0x8ee201a4,
-0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
-0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xace40000, 0xace50004, 0x8ee30608,
-0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018,
-0xace9001c, 0x318c0, 0x2463060c, 0x2e31021,
-0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120,
-0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
-0x24420001, 0x10430007, 0x0, 0x8ee24e34,
-0x24420001, 0x10a20005, 0x0, 0x80012d4,
-0x0, 0x14a00005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x80012ea,
-0x0, 0x8ee24e30, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x24020007, 0xac820000, 0x24020001,
-0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
-0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608,
-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
-0x800136d, 0x0, 0x8f830120, 0x27623800,
-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
-0x14c20007, 0x0, 0x8ee201a4, 0x3021,
-0x24420001, 0xaee201a4, 0x8001351, 0x8ee201a4,
-0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
-0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
-0x24020011, 0xac620018, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400037, 0x24060001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
-0x10a20005, 0x0, 0x800133b, 0x0,
-0x14a00005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400013, 0xac800000, 0x8001351, 0x0,
-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020012, 0xac820000, 0x24020001, 0xac820004,
-0x14c0001b, 0x0, 0x3c040001, 0x248451d0,
-0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
-0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
-0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0,
-0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608,
-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
-0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
-0x8ee20160, 0x3c040001, 0x248451e8, 0x3405f002,
-0x24420001, 0xaee20160, 0x8ee20160, 0x3021,
-0x3821, 0xafa00010, 0xc002403, 0xafa00014,
-0x96e6047a, 0x96e7046a, 0x3c040001, 0x24845200,
-0x24050012, 0xafa00010, 0xc002403, 0xafa00014,
-0xc004500, 0x0, 0xc002318, 0x0,
-0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228,
-0xaf40022c, 0x96e30458, 0x8ee40000, 0x3c0512d8,
-0x34a5c358, 0x27623800, 0xaee27258, 0x27623800,
-0xaee27260, 0x27623800, 0xaee27264, 0x3661021,
-0xaee27270, 0x2402ffff, 0xaee004d4, 0xaee004e0,
-0xaee004e4, 0xaee004f0, 0xa2e004f4, 0xaee00e0c,
-0xaee00e18, 0xaee00e10, 0xaee00e14, 0xaee00e1c,
-0xaee0724c, 0xaee05244, 0xaee05240, 0xaee0523c,
-0xaee07250, 0xaee07254, 0xaee0725c, 0xaee07268,
-0xaee004d0, 0x2463ffff, 0x852025, 0xaee304f8,
-0xaee40000, 0xaf800060, 0xaf820064, 0x3c020100,
-0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
-0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608,
-0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
-0xac43060c, 0xac440610, 0x8f870120, 0x27623800,
-0x24e80020, 0x102102b, 0x50400001, 0x27683000,
-0x8f820128, 0x11020004, 0x0, 0x8f820124,
-0x15020007, 0x1021, 0x8ee201a4, 0x3021,
-0x24420001, 0xaee201a4, 0x8001422, 0x8ee201a4,
-0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
-0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xace40000, 0xace50004, 0x8ee30608,
-0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018,
-0xace9001c, 0x318c0, 0x2463060c, 0x2e31021,
-0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120,
-0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
-0x24420001, 0x10430007, 0x0, 0x8ee24e34,
-0x24420001, 0x10a20005, 0x0, 0x800140c,
-0x0, 0x14a00005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x8001422,
-0x0, 0x8ee24e30, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x24020007, 0xac820000, 0x24020001,
-0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
-0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608,
-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
-0x80014a5, 0x0, 0x8f830120, 0x27623800,
-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
-0x14c20007, 0x0, 0x8ee201a4, 0x3021,
-0x24420001, 0xaee201a4, 0x8001489, 0x8ee201a4,
-0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
-0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
-0x24020011, 0xac620018, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400037, 0x24060001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
-0x10a20005, 0x0, 0x8001473, 0x0,
-0x14a00005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400013, 0xac800000, 0x8001489, 0x0,
-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020012, 0xac820000, 0x24020001, 0xac820004,
-0x14c0001b, 0x0, 0x3c040001, 0x248451d0,
-0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
-0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
-0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0,
-0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608,
-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
-0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
-0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc,
-0x8ee20154, 0x8f8200a0, 0x30420004, 0x1440fffd,
-0x0, 0x8f820040, 0x30420001, 0x14400008,
-0x0, 0x8f430104, 0x24020001, 0x10620004,
-0x0, 0x8f420264, 0x10400006, 0x0,
-0x8ee2017c, 0x24420001, 0xaee2017c, 0x80014c5,
-0x8ee2017c, 0x8f820044, 0x34420004, 0xaf820044,
-0x8ee20178, 0x24420001, 0xaee20178, 0x8ee20178,
-0x8f8200d8, 0x8f8300d4, 0x431023, 0xaee2726c,
-0x8ee2726c, 0x1c400003, 0x3c030001, 0x431021,
-0xaee2726c, 0xc004064, 0x0, 0xc004440,
-0xaf800228, 0x8fbf0024, 0x8fb00020, 0x3e00008,
-0x27bd0028, 0x3e00008, 0x0, 0x3e00008,
-0x0, 0x0, 0x0, 0x2402002c,
-0xaf820050, 0xaee07274, 0x8f420238, 0xaee27278,
-0x8f820054, 0x24420067, 0xaf820058, 0xaee07b88,
-0xaee07b8c, 0xaee07b84, 0x3c010001, 0x370821,
-0xac2083bc, 0x3c010001, 0x370821, 0x3e00008,
-0xa02083b9, 0x27bdffd8, 0xafbf0024, 0xafb00020,
-0x8f820054, 0x3c030001, 0x8c635cd8, 0x24420067,
-0x1060000d, 0xaf820058, 0x3c020001, 0x571021,
-0x904283b8, 0x10400005, 0x3c030200, 0x3c010001,
-0x370821, 0x8001503, 0xa02083b8, 0x8ee20000,
-0x431025, 0xaee20000, 0x8f420218, 0x30420100,
-0x104000c6, 0x0, 0x8f8200b0, 0x30420004,
-0x104000c2, 0x0, 0x3c030001, 0x771821,
-0x8c6383d0, 0x8f820104, 0x146200b4, 0x0,
-0x3c030001, 0x771821, 0x8c6383d4, 0x8f8200b4,
-0x146200ae, 0x0, 0x8f8200b0, 0x3c030080,
-0x431024, 0x1040000d, 0x0, 0x8f82011c,
-0x34420002, 0xaf82011c, 0x8f8200b0, 0x2403fffb,
-0x431024, 0xaf8200b0, 0x8f82011c, 0x2403fffd,
-0x431024, 0x80015cc, 0xaf82011c, 0x3c030001,
-0x771821, 0x8c6383d0, 0x8f820104, 0x14620082,
-0x0, 0x3c030001, 0x771821, 0x8c6383d4,
-0x8f8200b4, 0x1462007c, 0x0, 0x3c070001,
-0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001,
-0x24845270, 0xafa00014, 0xafa20010, 0x8f8600b0,
-0x3c050005, 0xc002403, 0x34a50900, 0x8f82011c,
-0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0,
-0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20006, 0x0, 0x8ee201a4,
-0x24420001, 0xaee201a4, 0x80015a0, 0x8ee201a4,
-0x8f440208, 0x8f45020c, 0x26e20030, 0xac620008,
-0x24020400, 0xa462000e, 0x2402000f, 0xac620018,
-0xac60001c, 0xac640000, 0xac650004, 0x8ee204c4,
-0xac620010, 0xaf860120, 0x92e24e20, 0x14400037,
-0x0, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
-0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
-0x0, 0x800158a, 0x0, 0x14a00005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
-0xac800000, 0x80015a0, 0x0, 0x8ee24e30,
-0x24030040, 0x24420001, 0x50430003, 0x1021,
-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x24020007,
-0xac820000, 0x24020001, 0xac820004, 0x8f82011c,
-0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201e4,
-0x3c070001, 0xf73821, 0x8ce783d0, 0x24420001,
-0xaee201e4, 0x8ee201e4, 0x3c040001, 0x2484527c,
-0x80015bd, 0xafa00010, 0x8f820104, 0x3c010001,
-0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001,
-0xf73821, 0x8ce783d0, 0x3c040001, 0x24845284,
-0x3c010001, 0x370821, 0xac2283d4, 0xafa00010,
-0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002403,
-0x34a50900, 0x80015cc, 0x0, 0x8f820104,
-0x3c010001, 0x370821, 0xac2283d0, 0x8f8200b4,
-0x3c010001, 0x370821, 0xac2283d4, 0x8ee27274,
-0x92e304f4, 0x24420067, 0x14600006, 0xaee27274,
-0x8ee27274, 0x8f430234, 0x43102b, 0x1440007b,
-0x0, 0x8ee304e4, 0x8ee204f8, 0x14620004,
-0x0, 0x92e204f4, 0x50400074, 0xa2e004f4,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
-0x8001637, 0x8ee201a4, 0x8ee204e4, 0xac62001c,
-0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008,
-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400037, 0x24100001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c830000, 0x24020012, 0x1462001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee54e30, 0x24420001, 0x10430007, 0x0,
-0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
-0x8001621, 0x0, 0x14a00005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x8001637, 0x0, 0x8ee24e30, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020012, 0xac820000,
-0x24020001, 0xac820004, 0x5600000b, 0x24100001,
-0x8ee204e4, 0x3c040001, 0x2484528c, 0xafa00014,
-0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
-0xc002403, 0x34a5f006, 0x16000003, 0x24020001,
-0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001,
-0xaee20170, 0x8ee20170, 0x8ee204e4, 0xa2e004f4,
-0xaee004f0, 0xaee07274, 0xaee204f8, 0x8ee20e1c,
-0x1040006d, 0x0, 0x8f830120, 0x27623800,
-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
-0x14c20007, 0x0, 0x8ee201a4, 0x8021,
-0x24420001, 0xaee201a4, 0x80016ad, 0x8ee201a4,
-0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac,
-0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
-0x24020011, 0xac620018, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400037, 0x24100001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
-0x10a20005, 0x0, 0x8001697, 0x0,
-0x14a00005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400013, 0xac800000, 0x80016ad, 0x0,
-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020012, 0xac820000, 0x24020001, 0xac820004,
-0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001,
-0x24845298, 0xafa00014, 0xafa20010, 0x8ee6724c,
-0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008,
-0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001,
-0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019,
-0x0, 0xaee04e24, 0x8f820040, 0x30420001,
-0x14400008, 0x0, 0x8f430104, 0x24020001,
-0x10620004, 0x0, 0x8f420264, 0x10400006,
-0x0, 0x8ee2017c, 0x24420001, 0xaee2017c,
-0x80016da, 0x8ee2017c, 0x8f820044, 0x34420004,
-0xaf820044, 0x8ee20178, 0x24420001, 0xaee20178,
-0x8ee20178, 0x8ee27278, 0x2442ff99, 0xaee27278,
-0x8ee27278, 0x1c4002ad, 0x0, 0x8f420238,
-0x104002aa, 0x0, 0x3c020001, 0x571021,
-0x904283e0, 0x144002a5, 0x0, 0x8f420080,
-0xaee2004c, 0x8f4200c0, 0xaee20048, 0x8f420084,
-0xaee20038, 0x8f420084, 0xaee20244, 0x8f420088,
-0xaee20248, 0x8f42008c, 0xaee2024c, 0x8f420090,
-0xaee20250, 0x8f420094, 0xaee20254, 0x8f420098,
-0xaee20258, 0x8f42009c, 0xaee2025c, 0x8f4200a0,
-0xaee20260, 0x8f4200a4, 0xaee20264, 0x8f4200a8,
-0xaee20268, 0x8f4200ac, 0xaee2026c, 0x8f4200b0,
-0xaee20270, 0x8f4200b4, 0xaee20274, 0x8f4200b8,
-0xaee20278, 0x8f4200bc, 0x24040001, 0xaee2027c,
-0xaee0003c, 0x41080, 0x571021, 0x8ee3003c,
-0x8c420244, 0x24840001, 0x621821, 0x2c82000f,
-0xaee3003c, 0x1440fff8, 0x41080, 0x8f4200cc,
-0xaee20050, 0x8f4200d0, 0xaee20054, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x8021, 0x24420001, 0xaee201a4, 0x8001775,
-0x8ee201a4, 0x8f440208, 0x8f45020c, 0x26e20030,
-0xac620008, 0x24020400, 0xa462000e, 0x2402000f,
-0xac620018, 0xac60001c, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400037, 0x24100001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c830000, 0x24020007,
-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
-0x10a20005, 0x0, 0x800175f, 0x0,
-0x14a00005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400013, 0xac800000, 0x8001775, 0x0,
-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020007, 0xac820000, 0x24020001, 0xac820004,
-0x12000212, 0x3c020400, 0xafa20018, 0x3c020001,
-0x571021, 0x904283b0, 0x1040010b, 0x0,
-0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff,
-0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0,
-0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
-0xac440610, 0x8f830054, 0x8f820054, 0x24690032,
-0x1221023, 0x2c420033, 0x1040006a, 0x5821,
-0x24180008, 0x240f000d, 0x240d0007, 0x240c0040,
-0x240e0001, 0x8f870120, 0x27623800, 0x24e80020,
-0x102102b, 0x50400001, 0x27683000, 0x8f820128,
-0x11020004, 0x0, 0x8f820124, 0x15020007,
-0x1021, 0x8ee201a4, 0x8021, 0x24420001,
-0xaee201a4, 0x80017f3, 0x8ee201a4, 0x8ee40608,
-0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
-0xa32821, 0xa3302b, 0x822021, 0x862021,
-0xace40000, 0xace50004, 0x8ee20608, 0xa4f8000e,
-0xacef0018, 0xacea001c, 0x210c0, 0x2442060c,
-0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010,
-0xaf880120, 0x92e24e20, 0x14400033, 0x24100001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x144d001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x80017e0,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400010, 0xac800000, 0x80017f3,
-0x0, 0x8ee24e30, 0x24420001, 0x504c0003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0xac8d0000, 0xac8e0004, 0x56000006, 0x240b0001,
-0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d,
-0x0, 0x316300ff, 0x24020001, 0x14620077,
-0x3c050009, 0xaeea0608, 0x8f830054, 0x8f820054,
-0x24690032, 0x1221023, 0x2c420033, 0x10400061,
-0x5821, 0x240d0008, 0x240c0011, 0x24080012,
-0x24070040, 0x240a0001, 0x8f830120, 0x27623800,
-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
-0x14c20007, 0x0, 0x8ee201a4, 0x8021,
-0x24420001, 0xaee201a4, 0x800185f, 0x8ee201a4,
-0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
-0x2462001c, 0xac620008, 0xa46d000e, 0xac6c0018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400033, 0x24100001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x1448001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x10470007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x800184c,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400010, 0xac800000, 0x800185f,
-0x0, 0x8ee24e30, 0x24420001, 0x50470003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0xac880000, 0xac8a0004, 0x56000006, 0x240b0001,
-0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
-0x0, 0x316300ff, 0x24020001, 0x14620003,
-0x3c050009, 0x800197c, 0x24100001, 0x3c040001,
-0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120,
-0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001,
-0x248452b0, 0xafa00010, 0xafa00014, 0x8f860120,
-0x8f870124, 0x34a5f010, 0xc002403, 0x8021,
-0x800197c, 0x0, 0x3c040001, 0x248452bc,
-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
-0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228,
-0x24420001, 0x304900ff, 0x512300e2, 0xafa00010,
-0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
-0x8fa4001c, 0xac43060c, 0xac440610, 0x8f870120,
-0x27623800, 0x24e80020, 0x102102b, 0x50400001,
-0x27683000, 0x8f820128, 0x11020004, 0x0,
-0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
-0x8021, 0x24420001, 0xaee201a4, 0x80018f7,
-0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
-0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0xace40000, 0xace50004,
-0x8ee30608, 0x24020008, 0xa4e2000e, 0x2402000d,
-0xace20018, 0xace9001c, 0x318c0, 0x2463060c,
-0x2e31021, 0xace20008, 0x8ee204c4, 0xace20010,
-0xaf880120, 0x92e24e20, 0x14400037, 0x24100001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c830000, 0x24020007, 0x1462001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee54e30, 0x24420001, 0x10430007, 0x0,
-0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
-0x80018e1, 0x0, 0x14a00005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x80018f7, 0x0, 0x8ee24e30, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020007, 0xac820000,
-0x24020001, 0xac820004, 0x5600000c, 0xaee90608,
-0x3c040001, 0x248452c8, 0xafa00010, 0xafa00014,
-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
-0x34a5f000, 0x800197c, 0x0, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x8021, 0x24420001, 0xaee201a4, 0x800195e,
-0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
-0x8ee504a4, 0x2462001c, 0xac620008, 0x24020008,
-0xa462000e, 0x24020011, 0xac620018, 0xac640000,
-0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
-0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
-0x24420001, 0x10430007, 0x0, 0x8ee24e34,
-0x24420001, 0x10a20005, 0x0, 0x8001948,
-0x0, 0x14a00005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x800195e,
-0x0, 0x8ee24e30, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x24020012, 0xac820000, 0x24020001,
-0xac820004, 0x5600001d, 0x24100001, 0x3c040001,
-0x248452d0, 0xafa00010, 0xafa00014, 0x8ee60608,
-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f001,
-0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c,
-0x8ee201b0, 0x3c040001, 0x248452dc, 0xafa00014,
-0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005,
-0xc002403, 0x0, 0x8ee201ac, 0x8021,
-0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c,
-0x24020001, 0x3c010001, 0x370821, 0xa02083b0,
-0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158,
-0x8ee30158, 0x800198c, 0xaee27278, 0x24020001,
-0x3c010001, 0x370821, 0xa02283b0, 0x3c020001,
-0x8c425cd8, 0x10400187, 0x0, 0x8ee27b84,
-0x24430001, 0x284200c9, 0x144001a4, 0xaee37b84,
-0x8ee204d4, 0x30420002, 0x14400119, 0xaee07b84,
-0x8ee204d4, 0x3c030600, 0x34631000, 0x34420002,
-0xaee204d4, 0xafa30018, 0x8ee20608, 0x8f430228,
-0x24420001, 0x304a00ff, 0x514300fd, 0xafa00010,
-0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
-0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054,
-0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
-0x1040006a, 0x5821, 0x24180008, 0x240f000d,
-0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120,
-0x27623800, 0x24e80020, 0x102102b, 0x50400001,
-0x27683000, 0x8f820128, 0x11020004, 0x0,
-0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
-0x8021, 0x24420001, 0xaee201a4, 0x8001a15,
-0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
-0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0xace40000, 0xace50004,
-0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c,
-0x210c0, 0x2442060c, 0x2e21021, 0xace20008,
-0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
-0x14400033, 0x24100001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c820000, 0x144d001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007,
-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
-0x0, 0x8001a02, 0x0, 0x14600005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
-0xac800000, 0x8001a15, 0x0, 0x8ee24e30,
-0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004,
-0x56000006, 0x240b0001, 0x8f820054, 0x1221023,
-0x2c420033, 0x1440ff9d, 0x0, 0x316300ff,
-0x24020001, 0x54620078, 0xafa00010, 0xaeea0608,
-0x8f830054, 0x8f820054, 0x24690032, 0x1221023,
-0x2c420033, 0x10400061, 0x5821, 0x240d0008,
-0x240c0011, 0x24080012, 0x24070040, 0x240a0001,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
-0x8001a81, 0x8ee201a4, 0x8ee20608, 0xac62001c,
-0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
-0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400033, 0x24100001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c820000, 0x1448001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007,
-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
-0x0, 0x8001a6e, 0x0, 0x14600005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
-0xac800000, 0x8001a81, 0x0, 0x8ee24e30,
-0x24420001, 0x50470003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0xac880000, 0xac8a0004,
-0x56000006, 0x240b0001, 0x8f820054, 0x1221023,
-0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
-0x24020001, 0x10620022, 0x0, 0x3c040001,
-0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120,
-0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011,
-0x8001aad, 0x0, 0x3c040001, 0x248452b0,
-0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
-0xc002403, 0x34a5f010, 0x8001aad, 0x0,
-0x3c040001, 0x248452bc, 0xafa00014, 0x8ee60608,
-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f,
-0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
-0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c,
-0x8ee204d4, 0x30420001, 0x10400055, 0x0,
-0x8f420218, 0x30420080, 0x10400029, 0x0,
-0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b7c,
-0x402821, 0x8ee200c0, 0x8ee300c4, 0x24060000,
-0x2407ffff, 0x2021, 0x461024, 0x1444000d,
-0x671824, 0x1465000b, 0x0, 0x8ee27b80,
-0x402821, 0x8ee200e0, 0x8ee300e4, 0x2021,
-0x461024, 0x14440003, 0x671824, 0x1065000b,
-0x0, 0x8ee200c0, 0x8ee300c4, 0x8ee400e0,
-0x8ee500e4, 0xaee37b7c, 0xaee57b80, 0x8f820044,
-0x38420020, 0x8001b38, 0xaf820044, 0x8f820044,
-0x2403ffdf, 0x431024, 0x8001b38, 0xaf820044,
-0x8f820044, 0x2403ffdf, 0x431024, 0xaf820044,
-0x8ee27b7c, 0x402821, 0x8ee200c0, 0x8ee300c4,
-0x24060000, 0x2407ffff, 0x2021, 0x461024,
-0x1444000d, 0x671824, 0x1465000b, 0x0,
-0x8ee27b80, 0x402821, 0x8ee200e0, 0x8ee300e4,
-0x2021, 0x461024, 0x14440003, 0x671824,
-0x1065000b, 0x0, 0x8ee200c0, 0x8ee300c4,
-0x8ee400e0, 0x8ee500e4, 0xaee37b7c, 0xaee57b80,
-0x8f820044, 0x38420040, 0x8001b38, 0xaf820044,
-0x8f820044, 0x34420040, 0x8001b38, 0xaf820044,
-0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b8c,
-0x24430001, 0x28420015, 0x14400028, 0xaee37b8c,
-0x8f820044, 0x38420020, 0xaf820044, 0x8001b38,
-0xaee07b8c, 0x8ee204d4, 0x30420001, 0x10400011,
-0x0, 0x8f420218, 0x30420080, 0x10400009,
-0x0, 0x8f820044, 0x34420020, 0xaf820044,
-0x8f820044, 0x2403ffbf, 0x431024, 0x8001b36,
-0xaf820044, 0x8f820044, 0x34420060, 0x8001b36,
-0xaf820044, 0x8f820044, 0x34420040, 0xaf820044,
-0x8ee27b88, 0x24430001, 0x28421389, 0x14400005,
-0xaee37b88, 0x8f820044, 0x38420020, 0xaf820044,
-0xaee07b88, 0xc004603, 0x0, 0x8fbf0024,
-0x8fb00020, 0x3e00008, 0x27bd0028, 0x27bdffb8,
-0xafbf0044, 0xafb60040, 0xafb5003c, 0xafb40038,
-0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028,
-0x8f960064, 0x32c20004, 0x1040000c, 0x24020004,
-0xaf820064, 0x8f420114, 0xaee204e0, 0x8f820060,
-0x34420008, 0xaf820060, 0x8ee2016c, 0x24420001,
-0xaee2016c, 0x80022f4, 0x8ee2016c, 0x32c20001,
-0x10400004, 0x24020001, 0xaf820064, 0x80022f4,
-0x0, 0x32c20002, 0x1440000c, 0x3c050003,
-0x3c040001, 0x24845354, 0x34a50001, 0x2c03021,
-0x3821, 0xafa00010, 0xc002403, 0xafa00014,
-0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c,
-0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c,
-0x21080, 0x5a1021, 0x8c420300, 0xafa20020,
-0x8f42022c, 0x24070001, 0x24420001, 0x3042003f,
-0x8001b80, 0xaf42022c, 0x3c040001, 0x24845360,
-0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003,
-0xc002403, 0x34a5f01f, 0x3821, 0x14e00003,
-0x0, 0x80022ed, 0xaf960064, 0x93a20020,
-0x2443ffff, 0x2c620011, 0x10400658, 0x31080,
-0x3c010001, 0x220821, 0x8c225418, 0x400008,
-0x0, 0x8fa20020, 0x30420fff, 0xaee20e0c,
-0x8f820060, 0x34420200, 0xaf820060, 0x8ee20118,
-0x24420001, 0xaee20118, 0x80022e8, 0x8ee20118,
-0x8fa20020, 0x24030001, 0x3c010001, 0x370821,
-0xa02383b1, 0x30420fff, 0xaee25238, 0x8f820060,
-0x34420100, 0xaf820060, 0x8ee20144, 0x24420001,
-0xaee20144, 0x80022e8, 0x8ee20144, 0x8fa20020,
-0x21200, 0x22502, 0x24020001, 0x10820005,
-0x24020002, 0x10820009, 0x2402fffe, 0x8001bc9,
-0xafa00010, 0x8ee204d4, 0xaee40070, 0xaee40074,
-0x34420001, 0x8001bbd, 0xaee204d4, 0x8ee304d4,
-0xaee40070, 0xaee40074, 0x621824, 0xaee304d4,
-0x8f840054, 0x41442, 0x41c82, 0x431021,
-0x41cc2, 0x431023, 0x41d02, 0x431021,
-0x41d42, 0x431023, 0x8001bd0, 0xaee20078,
-0x3c040001, 0x2484536c, 0xafa00014, 0x8fa60020,
-0x3c050003, 0xc002403, 0x34a50004, 0x8ee20110,
-0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110,
-0x27440212, 0xc0022fe, 0x24050006, 0x3049001f,
-0x920c0, 0x2e41021, 0x9442727c, 0x30424000,
-0x1040000a, 0x971021, 0x97430212, 0xa443727e,
-0x8f430214, 0x971021, 0xac437280, 0x2e41821,
-0x34028000, 0x8001c79, 0xa462727c, 0x9443727e,
-0x97420212, 0x14620006, 0x2e41021, 0x971021,
-0x8c437280, 0x8f420214, 0x1062009f, 0x2e41021,
-0x9442727c, 0x30428000, 0x1040002a, 0x2406ffff,
-0x2021, 0x410c0, 0x2e21021, 0x9442737c,
-0x30424000, 0x54400005, 0x803021, 0x24840001,
-0x2c820080, 0x1440fff8, 0x410c0, 0x4c10010,
-0x618c0, 0x610c0, 0x571821, 0x8c63737c,
-0x571021, 0xafa30010, 0x8c427380, 0x3c040001,
-0x24845378, 0xafa20014, 0x8f470214, 0x3c050003,
-0xc002403, 0x34a50013, 0x8001c90, 0x3c020800,
-0x97440212, 0x771021, 0xa444737e, 0x8f440214,
-0x771021, 0x2e31821, 0xac447380, 0x34028000,
-0xa462737c, 0x910c0, 0x2e21021, 0x8001c79,
-0xa446727c, 0x2e41021, 0x9445727c, 0x8001c2e,
-0x510c0, 0x9443737e, 0x97420212, 0x14620006,
-0x510c0, 0x971021, 0x8c437380, 0x8f420214,
-0x10620065, 0x510c0, 0x2e21021, 0x9445737c,
-0x510c0, 0x2e21021, 0x9442737c, 0x30428000,
-0x1040fff0, 0x971021, 0x520c0, 0x971021,
-0x9443737e, 0x97420212, 0x14620006, 0x2406ffff,
-0x971021, 0x8c437380, 0x8f420214, 0x10620053,
-0x3c020800, 0x2021, 0x410c0, 0x2e21021,
-0x9442737c, 0x30424000, 0x54400005, 0x803021,
-0x24840001, 0x2c820080, 0x1440fff8, 0x410c0,
-0x4c10023, 0x618c0, 0x910c0, 0x571821,
-0x8c63727c, 0x571021, 0xafa30010, 0x8c427280,
-0x3c040001, 0x24845384, 0xafa20014, 0x8f470214,
-0x3c050003, 0xc002403, 0x34a5f017, 0x8001c90,
-0x3c020800, 0x8f430210, 0xb71021, 0xac43777c,
-0x8f430214, 0xb71021, 0xac437780, 0x3c020001,
-0x571021, 0x8c4283b4, 0x24420001, 0x3c010001,
-0x370821, 0xac2283b4, 0x3c030001, 0x771821,
-0x8c6383b4, 0x2e51021, 0x8001c82, 0xa443777c,
-0x97440212, 0x771021, 0xa444737e, 0x8f440214,
-0x771021, 0x2e31821, 0xac447380, 0x34028000,
-0xa462737c, 0x510c0, 0x2e21021, 0xa446737c,
-0x2021, 0x428c0, 0x2e51021, 0x9442777c,
-0x1040ffdc, 0x24840001, 0x2c820080, 0x5440fffa,
-0x428c0, 0x92e204d8, 0x10400006, 0x24020001,
-0x8ee304dc, 0x1221004, 0x621825, 0x8001c8f,
-0xaee304dc, 0x8f830228, 0x24020001, 0x1221004,
-0x621825, 0xaf830228, 0x3c020800, 0x34421000,
-0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
-0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608,
-0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
-0xac43060c, 0xac440610, 0x8f830054, 0x8f820054,
-0x24690032, 0x1221023, 0x2c420033, 0x1040006a,
-0x5821, 0x24100008, 0x240f000d, 0x240d0007,
-0x240c0040, 0x240e0001, 0x8f870120, 0x27623800,
-0x24e80020, 0x102102b, 0x50400001, 0x27683000,
-0x8f820128, 0x11020004, 0x0, 0x8f820124,
-0x15020007, 0x1021, 0x8ee201a4, 0x3821,
-0x24420001, 0xaee201a4, 0x8001d08, 0x8ee201a4,
-0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
-0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xace40000, 0xace50004, 0x8ee20608,
-0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0,
-0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4,
-0xace20010, 0xaf880120, 0x92e24e20, 0x14400033,
-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c820000, 0x144d001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
-0x8001cf5, 0x0, 0x14600005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
-0x8001d08, 0x0, 0x8ee24e30, 0x24420001,
-0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006,
-0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
-0x1440ff9d, 0x0, 0x316300ff, 0x24020001,
-0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054,
-0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
-0x10400061, 0x5821, 0x240e0008, 0x240d0011,
-0x240a0012, 0x24080040, 0x240c0001, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x3821, 0x24420001, 0xaee201a4, 0x8001d74,
-0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
-0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e,
-0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4,
-0xac620010, 0xaf860120, 0x92e24e20, 0x14400033,
-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c820000, 0x144a001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x10480007, 0x0,
-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
-0x8001d61, 0x0, 0x14600005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
-0x8001d74, 0x0, 0x8ee24e30, 0x24420001,
-0x50480003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
-0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
-0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
-0x10620022, 0x0, 0x3c040001, 0x24845390,
-0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
-0x3c050009, 0xc002403, 0x34a5f011, 0x8001da0,
-0x0, 0x3c040001, 0x2484539c, 0xafa00014,
-0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
-0x34a5f010, 0x8001da0, 0x0, 0x3c040001,
-0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228,
-0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
-0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124,
-0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124,
-0x27440212, 0xc0022fe, 0x24050006, 0x3049001f,
-0x928c0, 0x2e51021, 0x9442727c, 0x30428000,
-0x1040002f, 0x2e51021, 0x9442727c, 0x30424000,
-0x1440001c, 0xb71021, 0x9443727e, 0x97420212,
-0x14620018, 0xb71021, 0x8c437280, 0x8f420214,
-0x54620016, 0xafa20010, 0x92e204d8, 0x10400007,
-0x24020001, 0x8ee304dc, 0x1221004, 0x21027,
-0x621824, 0x8001dc9, 0xaee304dc, 0x8f830228,
-0x1221004, 0x21027, 0x621824, 0xaf830228,
-0x910c0, 0x2e21821, 0x3402c000, 0x8001e4e,
-0xa462727c, 0x8f420214, 0xafa20010, 0x910c0,
-0x571021, 0x8c42727c, 0x3c040001, 0x248453b4,
-0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c,
-0xc002403, 0x1203021, 0x8001e83, 0x3c020800,
-0xb71021, 0x9443727e, 0x97420212, 0x14620019,
-0x918c0, 0xb71021, 0x8c437280, 0x8f420214,
-0x14620014, 0x918c0, 0x2e51021, 0x9447727c,
-0x720c0, 0x971021, 0x9443737e, 0xb71021,
-0xa443727e, 0x971021, 0x8c437380, 0xb71021,
-0xac437280, 0x2e41021, 0x9443737c, 0x2e51021,
-0xa443727c, 0x2e41821, 0x3402c000, 0x8001e4e,
-0xa462737c, 0x2e31021, 0x9447727c, 0x3021,
-0x720c0, 0x2e41021, 0x9442737c, 0x4021,
-0x30428000, 0x14400025, 0xe02821, 0x605021,
-0x340bc000, 0x971021, 0x9443737e, 0x97420212,
-0x54620015, 0xe02821, 0x971021, 0x8c437380,
-0x8f420214, 0x54620010, 0xe02821, 0x11000006,
-0x2e41021, 0x9443737c, 0x510c0, 0x2e21021,
-0x8001e1a, 0xa443737c, 0x9443737c, 0x2ea1021,
-0xa443727c, 0x710c0, 0x2e21021, 0xa44b737c,
-0x8001e28, 0x24060001, 0x510c0, 0x2e21021,
-0x9447737c, 0x720c0, 0x2e41021, 0x9442737c,
-0x30428000, 0x1040ffdf, 0x25080001, 0x30c200ff,
-0x14400025, 0x2021, 0x720c0, 0x971021,
-0x9443737e, 0x97420212, 0x1462000f, 0x910c0,
-0x971021, 0x8c437380, 0x8f420214, 0x1462000a,
-0x910c0, 0x2e41821, 0x3402c000, 0x15000015,
-0xa462737c, 0x910c0, 0x2e21821, 0x34028000,
-0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c,
-0x3c040001, 0x248453c0, 0x3c050003, 0xafa20010,
-0x710c0, 0x571021, 0x8c42737c, 0x34a5001e,
-0x1203021, 0xc002403, 0xafa20014, 0x8001e83,
-0x3c020800, 0x2021, 0x428c0, 0xb71021,
-0x9443777e, 0x97420212, 0x5462002b, 0x24840001,
-0xb71021, 0x8c437780, 0x8f420214, 0x54620026,
-0x24840001, 0x3c020001, 0x571021, 0x8c4283b4,
-0x2442ffff, 0x3c010001, 0x370821, 0xac2283b4,
-0x3c020001, 0x571021, 0x8c4283b4, 0x809021,
-0x242102b, 0x1040000e, 0x24b1777c, 0x24b07784,
-0x2f02021, 0x2f12821, 0xc002490, 0x24060008,
-0x26310008, 0x3c020001, 0x571021, 0x8c4283b4,
-0x26520001, 0x242102b, 0x1440fff5, 0x26100008,
-0x3c040001, 0x972021, 0x8c8483b4, 0x24050008,
-0x420c0, 0x2484777c, 0xc002488, 0x2e42021,
-0x8001e83, 0x3c020800, 0x2c820080, 0x1440ffcf,
-0x428c0, 0x3c020800, 0x34422000, 0xafa20018,
-0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff,
-0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0,
-0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
-0xac440610, 0x8f830054, 0x8f820054, 0x24690032,
-0x1221023, 0x2c420033, 0x1040006a, 0x5821,
-0x24100008, 0x240f000d, 0x240d0007, 0x240c0040,
-0x240e0001, 0x8f870120, 0x27623800, 0x24e80020,
-0x102102b, 0x50400001, 0x27683000, 0x8f820128,
-0x11020004, 0x0, 0x8f820124, 0x15020007,
-0x1021, 0x8ee201a4, 0x3821, 0x24420001,
-0xaee201a4, 0x8001efb, 0x8ee201a4, 0x8ee40608,
-0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
-0xa32821, 0xa3302b, 0x822021, 0x862021,
-0xace40000, 0xace50004, 0x8ee20608, 0xa4f0000e,
-0xacef0018, 0xacea001c, 0x210c0, 0x2442060c,
-0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010,
-0xaf880120, 0x92e24e20, 0x14400033, 0x24070001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x144d001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x8001ee8,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400010, 0xac800000, 0x8001efb,
-0x0, 0x8ee24e30, 0x24420001, 0x504c0003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0xac8d0000, 0xac8e0004, 0x54e00006, 0x240b0001,
-0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d,
-0x0, 0x316300ff, 0x24020001, 0x54620078,
-0xafa00010, 0xaeea0608, 0x8f830054, 0x8f820054,
-0x24690032, 0x1221023, 0x2c420033, 0x10400061,
-0x5821, 0x240e0008, 0x240d0011, 0x240a0012,
-0x24080040, 0x240c0001, 0x8f830120, 0x27623800,
-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
-0x14c20007, 0x0, 0x8ee201a4, 0x3821,
-0x24420001, 0xaee201a4, 0x8001f67, 0x8ee201a4,
-0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
-0x2462001c, 0xac620008, 0xa46e000e, 0xac6d0018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400033, 0x24070001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x144a001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x10480007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x8001f54,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400010, 0xac800000, 0x8001f67,
-0x0, 0x8ee24e30, 0x24420001, 0x50480003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001,
-0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
-0x0, 0x316300ff, 0x24020001, 0x10620022,
-0x0, 0x3c040001, 0x24845390, 0xafa00010,
-0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
-0xc002403, 0x34a5f011, 0x8001f93, 0x0,
-0x3c040001, 0x2484539c, 0xafa00014, 0x8f860120,
-0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010,
-0x8001f93, 0x0, 0x3c040001, 0x248453a8,
-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
-0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001,
-0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001,
-0xaee20128, 0x8ee20128, 0x8ee20164, 0x24420001,
-0xaee20164, 0x80022e8, 0x8ee20164, 0x8fa20020,
-0x21200, 0x21d02, 0x24020001, 0x10620005,
-0x24020002, 0x1062000d, 0x0, 0x8001fb7,
-0xafa00010, 0x92e204d8, 0x14400006, 0x24020001,
-0x8f820228, 0xaee204dc, 0x2402ffff, 0xaf820228,
-0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8,
-0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228,
-0x8001fbe, 0xa2e004d8, 0x3c040001, 0x248453c8,
-0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
-0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c,
-0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200,
-0x22502, 0x24020001, 0x10820005, 0x24020002,
-0x1082000f, 0x0, 0x8001fe3, 0xafa00010,
-0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
-0x34420008, 0xaf820220, 0x24020001, 0x3c010001,
-0x370821, 0xa02283b2, 0x8001fea, 0xaee40108,
-0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024,
-0xaf820220, 0x3c010001, 0x370821, 0xa02083b2,
-0x8001fea, 0xaee40108, 0x3c040001, 0x248453d4,
-0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
-0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c,
-0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200,
-0x21d02, 0x24020001, 0x10620005, 0x24020002,
-0x1062000e, 0x0, 0x8002011, 0xafa00010,
-0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
-0x34420008, 0xaf820220, 0x24020001, 0x3c010001,
-0x370821, 0x8002018, 0xa02283b3, 0x3c020001,
-0x571021, 0x904283b2, 0x3c010001, 0x370821,
-0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff,
-0x3463fff7, 0x431024, 0x8002018, 0xaf820220,
-0x3c040001, 0x248453e0, 0xafa00014, 0x8fa60020,
-0x3c050003, 0xc002403, 0x34a5f00b, 0x8ee20114,
-0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114,
-0x27840208, 0x27450200, 0xc00249a, 0x24060008,
-0x26e40094, 0x27450200, 0xc00249a, 0x24060008,
-0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8,
-0x8ee20134, 0x8f460248, 0x2021, 0xc005108,
-0x24050004, 0x8ee20130, 0x24420001, 0xaee20130,
-0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0,
-0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001,
-0xaee20140, 0x8ef00140, 0x8ef10074, 0x8ef20070,
-0xc002488, 0x24050400, 0xaef301cc, 0xaef401d0,
-0xaef501d8, 0xaef00140, 0xaef10074, 0xaef20070,
-0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260,
-0x27450200, 0x24060008, 0xaee20068, 0x24020006,
-0xc00249a, 0xaee20064, 0x3c023b9a, 0x3442ca00,
-0xaee2006c, 0x240203e8, 0x24040002, 0x24030001,
-0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220,
-0x30420008, 0x10400004, 0x0, 0xaee30108,
-0x8002061, 0x2021, 0xaee40108, 0x2021,
-0x3c030001, 0x641821, 0x90635c30, 0x2e41021,
-0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8,
-0x0, 0x8f820040, 0x2e41821, 0x24840001,
-0x21702, 0x24420030, 0xa062009c, 0x2e41021,
-0x80022e8, 0xa040009c, 0x24020001, 0x3c010001,
-0x370821, 0xa02283e0, 0x240b0400, 0x24080014,
-0x240a0040, 0x24090001, 0x8f830100, 0x27623000,
-0x24660020, 0xc2102b, 0x50400001, 0x27662800,
-0x8f820108, 0x10c20004, 0x0, 0x8f820104,
-0x14c20007, 0x26e20030, 0x8ee201a8, 0x3821,
-0x24420001, 0xaee201a8, 0x80020a8, 0x8ee201a8,
-0x8ee404b8, 0x8ee504bc, 0xac620008, 0xa46b000e,
-0xac680018, 0xac60001c, 0xac640000, 0xac650004,
-0x8ee204cc, 0xac620010, 0xaf860100, 0x92e204ec,
-0x1440000e, 0x24070001, 0x8ee24e28, 0x24420001,
-0x504a0003, 0x1021, 0x8ee24e28, 0x24420001,
-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e21021, 0xac480000, 0xac490004, 0x10e0ffd2,
-0x0, 0x80022e8, 0x0, 0x3c020900,
-0xaee05238, 0xaee0523c, 0xaee05240, 0xaee05244,
-0xaee001d0, 0x3c010001, 0x370821, 0xa02083b1,
-0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
-0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608,
-0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
-0xac43060c, 0xac440610, 0x8f830054, 0x8f820054,
-0x24690032, 0x1221023, 0x2c420033, 0x1040006a,
-0x5821, 0x24100008, 0x240f000d, 0x240d0007,
-0x240c0040, 0x240e0001, 0x8f870120, 0x27623800,
-0x24e80020, 0x102102b, 0x50400001, 0x27683000,
-0x8f820128, 0x11020004, 0x0, 0x8f820124,
-0x15020007, 0x1021, 0x8ee201a4, 0x3821,
-0x24420001, 0xaee201a4, 0x800212c, 0x8ee201a4,
-0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
-0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xace40000, 0xace50004, 0x8ee20608,
-0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0,
-0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4,
-0xace20010, 0xaf880120, 0x92e24e20, 0x14400033,
-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c820000, 0x144d001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
-0x8002119, 0x0, 0x14600005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
-0x800212c, 0x0, 0x8ee24e30, 0x24420001,
-0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006,
-0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
-0x1440ff9d, 0x0, 0x316300ff, 0x24020001,
-0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054,
-0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
-0x10400061, 0x5821, 0x240e0008, 0x240d0011,
-0x240a0012, 0x24080040, 0x240c0001, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x3821, 0x24420001, 0xaee201a4, 0x8002198,
-0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
-0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e,
-0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4,
-0xac620010, 0xaf860120, 0x92e24e20, 0x14400033,
-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c820000, 0x144a001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x10480007, 0x0,
-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
-0x8002185, 0x0, 0x14600005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
-0x8002198, 0x0, 0x8ee24e30, 0x24420001,
-0x50480003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
-0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
-0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
-0x10620022, 0x0, 0x3c040001, 0x24845390,
-0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
-0x3c050009, 0xc002403, 0x34a5f011, 0x80021c4,
-0x0, 0x3c040001, 0x2484539c, 0xafa00014,
-0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
-0x34a5f010, 0x80021c4, 0x0, 0x3c040001,
-0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228,
-0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
-0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120,
-0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168,
-0x24420001, 0xaee20168, 0x80022e8, 0x8ee20168,
-0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260,
-0x27450200, 0x24060008, 0xc00249a, 0xaee20068,
-0x8f820220, 0x30420008, 0x14400002, 0x24020001,
-0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001,
-0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001,
-0x248453ec, 0xafa00010, 0xafa00014, 0x8fa60020,
-0x3c050003, 0xc002403, 0x34a5f00f, 0x93a20020,
-0x3c030700, 0x34631000, 0x431025, 0xafa20018,
-0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff,
-0x512300e2, 0xafa00010, 0x8ee20608, 0x210c0,
-0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
-0xac440610, 0x8f870120, 0x27623800, 0x24e80020,
-0x102102b, 0x50400001, 0x27683000, 0x8f820128,
-0x11020004, 0x0, 0x8f820124, 0x15020007,
-0x1021, 0x8ee201a4, 0x3821, 0x24420001,
-0xaee201a4, 0x800225d, 0x8ee201a4, 0x8ee40608,
-0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
-0xa32821, 0xa3302b, 0x822021, 0x862021,
-0xace40000, 0xace50004, 0x8ee30608, 0x24020008,
-0xa4e2000e, 0x2402000d, 0xace20018, 0xace9001c,
-0x318c0, 0x2463060c, 0x2e31021, 0xace20008,
-0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
-0x14400037, 0x24070001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c830000, 0x24020007,
-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
-0x10a20005, 0x0, 0x8002247, 0x0,
-0x14a00005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400013, 0xac800000, 0x800225d, 0x0,
-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020007, 0xac820000, 0x24020001, 0xac820004,
-0x54e0000c, 0xaee90608, 0x3c040001, 0x248453f4,
-0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
-0x3c050009, 0xc002403, 0x34a5f000, 0x80022e0,
-0x0, 0x8f830120, 0x27623800, 0x24660020,
-0xc2102b, 0x50400001, 0x27663000, 0x8f820128,
-0x10c20004, 0x0, 0x8f820124, 0x14c20007,
-0x0, 0x8ee201a4, 0x3821, 0x24420001,
-0xaee201a4, 0x80022c4, 0x8ee201a4, 0x8ee20608,
-0xac62001c, 0x8ee404a0, 0x8ee504a4, 0x2462001c,
-0xac620008, 0x24020008, 0xa462000e, 0x24020011,
-0xac620018, 0xac640000, 0xac650004, 0x8ee204c4,
-0xac620010, 0xaf860120, 0x92e24e20, 0x14400037,
-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c830000, 0x24020012, 0x1462001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
-0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
-0x0, 0x80022ae, 0x0, 0x14a00005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
-0xac800000, 0x80022c4, 0x0, 0x8ee24e30,
-0x24030040, 0x24420001, 0x50430003, 0x1021,
-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x24020012,
-0xac820000, 0x24020001, 0xac820004, 0x14e0001b,
-0x0, 0x3c040001, 0x248453fc, 0xafa00010,
-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
-0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001,
-0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001,
-0x24845408, 0xafa00014, 0x8ee60608, 0x8f470228,
-0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201ac,
-0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150,
-0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160,
-0x24420001, 0xaee20160, 0x8ee20160, 0x8f43022c,
-0x8f42010c, 0x14620009, 0x24020002, 0xaf820064,
-0x8f820064, 0x14400005, 0x0, 0x8f43022c,
-0x8f42010c, 0x1462f875, 0x0, 0x8fbf0044,
-0x8fb60040, 0x8fb5003c, 0x8fb40038, 0x8fb30034,
-0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x3e00008,
-0x27bd0048, 0x27bdfff8, 0x2408ffff, 0x10a00014,
-0x4821, 0x3c0aedb8, 0x354a8320, 0x90870000,
-0x24840001, 0x3021, 0x1071026, 0x30420001,
-0x10400002, 0x81842, 0x6a1826, 0x604021,
-0x24c60001, 0x2cc20008, 0x1440fff7, 0x73842,
-0x25290001, 0x125102b, 0x1440fff0, 0x0,
-0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffe8,
-0x27642800, 0xafbf0010, 0xc002488, 0x24051000,
-0x24020021, 0xaf800100, 0xaf800104, 0xaf800108,
-0xaf800110, 0xaf800114, 0xaf800118, 0xaf800120,
-0xaf800124, 0xaf800128, 0xaf800130, 0xaf800134,
-0xaf800138, 0xaee04e28, 0xaee04e2c, 0xaee04e30,
-0xaee04e34, 0xaf82011c, 0x8f420218, 0x30420040,
-0x10400004, 0x0, 0x8f82011c, 0x34420004,
-0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018,
-0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010,
-0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0,
-0x8f87011c, 0x3c040001, 0x248454c0, 0xc002403,
-0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824,
-0x3c020400, 0x10620029, 0x43102b, 0x14400008,
-0x3c022000, 0x3c020100, 0x10620024, 0x3c020200,
-0x10620011, 0x0, 0x8002374, 0x0,
-0x10620008, 0x3c024000, 0x1462001c, 0x0,
-0x8ee20190, 0x24420001, 0xaee20190, 0x8002374,
-0x8ee20190, 0x8ee2018c, 0x24420001, 0xaee2018c,
-0x8002374, 0x8ee2018c, 0x8f82011c, 0x34420002,
-0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001,
-0xaf8200b0, 0xaf830104, 0x8f82011c, 0x2403fffd,
-0x431024, 0xaf82011c, 0x8ee201a0, 0x24420001,
-0xaee201a0, 0x8002377, 0x8ee201a0, 0x8f8200b0,
-0x34420001, 0xaf8200b0, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x27bdffe0, 0xafbf001c, 0xafb00018,
-0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001,
-0xafa20014, 0x8f8600a0, 0x8f87011c, 0x3c040001,
-0x248454cc, 0xc002403, 0x34a5f000, 0x8f8300a0,
-0x3c027f00, 0x621824, 0x3c020400, 0x10620053,
-0x8021, 0x43102b, 0x14400008, 0x3c042000,
-0x3c020100, 0x1062004d, 0x3c020200, 0x1062003a,
-0x0, 0x80023e0, 0x0, 0x10640003,
-0x3c024000, 0x14620045, 0x0, 0x8f8200a0,
-0x441024, 0x10400006, 0x0, 0x8ee20194,
-0x24420001, 0xaee20194, 0x80023a9, 0x8ee20194,
-0x8ee20198, 0x24420001, 0xaee20198, 0x8ee20198,
-0x8f82011c, 0x34420002, 0xaf82011c, 0x8f82011c,
-0x30420200, 0x1040001b, 0x0, 0x8f8300a0,
-0x8f840124, 0x8f8200ac, 0x14400007, 0x24020001,
-0x3c020001, 0x3442f000, 0x621024, 0x50400001,
-0x24100001, 0x24020001, 0x1200000d, 0xaf8200a0,
-0x8f820124, 0x2442ffe0, 0xaf820124, 0x8f820124,
-0x8f820124, 0x27633000, 0x43102b, 0x10400005,
-0x276237e0, 0xaf820124, 0x80023ca, 0x0,
-0xaf840124, 0x8f82011c, 0x2403fffd, 0x431024,
-0x80023e3, 0xaf82011c, 0x8f82011c, 0x34420002,
-0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001,
-0xaf8200a0, 0xaf830124, 0x8f82011c, 0x2403fffd,
-0x431024, 0xaf82011c, 0x8ee2019c, 0x24420001,
-0xaee2019c, 0x80023e3, 0x8ee2019c, 0x8f8200a0,
-0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018,
-0x3e00008, 0x27bd0020, 0x0, 0x3c020001,
-0x8c425c58, 0x27bdffe8, 0xafbf0014, 0x14400012,
-0xafb00010, 0x3c100001, 0x26105dd0, 0x2002021,
-0xc002488, 0x24052000, 0x26021fe0, 0x3c010001,
-0xac225d94, 0x3c010001, 0xac225d90, 0xaf420250,
-0x24022000, 0xaf500254, 0xaf420258, 0x24020001,
-0x3c010001, 0xac225c58, 0x8fbf0014, 0x8fb00010,
-0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635d94,
-0x8c820000, 0x8fa80010, 0x8fa90014, 0xac620000,
-0x3c020001, 0x8c425d94, 0x8c830004, 0xac430004,
-0xac450008, 0x8f840054, 0x2443ffe0, 0xac460010,
-0xac470014, 0xac480018, 0xac49001c, 0x3c010001,
-0xac235d94, 0xac44000c, 0x3c020001, 0x24425dd0,
-0x62182b, 0x10600005, 0x0, 0x3c020001,
-0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
-0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000,
-0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40,
-0xac620004, 0x3e00008, 0xaf430250, 0x3c030001,
-0x8c635d94, 0x3c020001, 0x8c425c40, 0x27bdffd0,
-0xafb40020, 0x8fb40040, 0xafb00010, 0x808021,
-0xafb50024, 0x8fb50044, 0x8fa40048, 0xafb10014,
-0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018,
-0xac620000, 0x3c050001, 0x8ca55d94, 0x3c020001,
-0x8c425c40, 0xc09021, 0xe09821, 0x10800006,
-0xaca20004, 0x24a50008, 0xc002490, 0x24060018,
-0x800244e, 0x0, 0x24a40008, 0xc002488,
-0x24050018, 0x3c020001, 0x8c425d94, 0x3c050001,
-0x24a55dd0, 0x2442ffe0, 0x3c010001, 0xac225d94,
-0x45102b, 0x10400005, 0x0, 0x3c020001,
-0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
-0x8c635d94, 0x8e020000, 0xac620000, 0x3c030001,
-0x8c635d94, 0x8e020004, 0xac620004, 0xac710008,
-0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225d94,
-0x45102b, 0xac720010, 0xac730014, 0xac740018,
-0xac75001c, 0x10400005, 0xac64000c, 0x3c020001,
-0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
-0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000,
-0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40,
-0xac620004, 0xaf430250, 0x8fbf0028, 0x8fb50024,
-0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
-0x8fb00010, 0x3e00008, 0x27bd0030, 0x10a00005,
-0x0, 0xac800000, 0x24a5fffc, 0x14a0fffd,
-0x24840004, 0x3e00008, 0x0, 0x10c00007,
-0x0, 0x8c820000, 0x24840004, 0x24c6fffc,
-0xaca20000, 0x14c0fffb, 0x24a50004, 0x3e00008,
-0x0, 0x10c00007, 0x0, 0x8ca20000,
-0x24a50004, 0x24c6fffc, 0xac820000, 0x14c0fffb,
-0x24840004, 0x3e00008, 0x0, 0x3e00008,
-0x0, 0x27bdffd8, 0xafbf0020, 0x8ee304e4,
-0x8ee204e0, 0x10620436, 0x0, 0x8ee204e4,
-0x8ee304fc, 0x21100, 0x626021, 0x95870008,
-0x8d8a0000, 0x8d8b0004, 0x958d000a, 0x8ee2725c,
-0x8ee3726c, 0x30e4ffff, 0x441021, 0x62182b,
-0x10600015, 0x31a20004, 0x8f8200d8, 0x8ee37258,
-0x431023, 0xaee2726c, 0x8ee2726c, 0x1c400003,
-0x3c030001, 0x431021, 0xaee2726c, 0x8ee2725c,
-0x8ee3726c, 0x441021, 0x62182b, 0x10600006,
-0x31a20004, 0x8ee201b8, 0x24420001, 0xaee201b8,
-0x80028e1, 0x8ee201b8, 0x10400240, 0x31a20200,
-0x1040014d, 0x4821, 0x96e2045a, 0x30420010,
-0x10400149, 0x0, 0x8f840100, 0x27623000,
-0x24850020, 0xa2102b, 0x50400001, 0x27652800,
-0x8f820108, 0x10a20004, 0x0, 0x8f820104,
-0x14a20006, 0x2402000c, 0x8ee201a8, 0x24420001,
-0xaee201a8, 0x800252c, 0x8ee201a8, 0xac8a0000,
-0xac8b0004, 0x8ee37264, 0x24060005, 0xa482000e,
-0xac860018, 0xac830008, 0x8ee204e4, 0xac82001c,
-0x8ee204c8, 0xac820010, 0xaf850100, 0x92e204ec,
-0x14400036, 0x24090001, 0x8ee24e28, 0x210c0,
-0x24424e38, 0x2e22021, 0x8c820000, 0x1446001f,
-0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b,
-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007,
-0x0, 0x8ee24e2c, 0x24420001, 0x10a20005,
-0x0, 0x8002516, 0x0, 0x14a00005,
-0x0, 0x8f820108, 0x24420020, 0xaf820108,
-0x8f820108, 0x8c820004, 0x2c420011, 0x50400013,
-0xac800000, 0x800252c, 0x0, 0x8ee24e28,
-0x24030040, 0x24420001, 0x50430003, 0x1021,
-0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28,
-0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
-0xac820000, 0x24020001, 0xac820004, 0x1520000a,
-0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001,
-0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4,
-0x80028be, 0x34a5f114, 0x8ee27264, 0x34843800,
-0x3641821, 0x24420010, 0x43102b, 0x14400073,
-0x0, 0x8ee27264, 0x24480010, 0x3641021,
-0x102102b, 0x14400002, 0x3c02ffff, 0x1024021,
-0x8f850100, 0x27623000, 0x24a60020, 0xc2102b,
-0x50400001, 0x27662800, 0x8f820108, 0x10c20004,
-0x0, 0x8f820104, 0x14c20007, 0x2563000c,
-0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8,
-0x80025a0, 0x8ee201a8, 0x2c64000c, 0x1441021,
-0xaca20000, 0xaca30004, 0x24e2fff4, 0xa4a2000e,
-0x24020006, 0xaca80008, 0xaca20018, 0x8ee204e4,
-0xaca2001c, 0x8ee204c8, 0x3c030002, 0x431025,
-0xaca20010, 0xaf860100, 0x92e204ec, 0x14400037,
-0x24090001, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e22021, 0x8c830000, 0x24020005, 0x1462001f,
-0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b,
-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007,
-0x0, 0x8ee24e2c, 0x24420001, 0x10a20005,
-0x0, 0x800258a, 0x0, 0x14a00005,
-0x0, 0x8f820108, 0x24420020, 0xaf820108,
-0x8f820108, 0x8c820004, 0x2c420011, 0x50400013,
-0xac800000, 0x80025a0, 0x0, 0x8ee24e28,
-0x24030040, 0x24420001, 0x50430003, 0x1021,
-0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28,
-0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
-0xac820000, 0x24020001, 0xac820004, 0x1520000a,
-0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001,
-0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4,
-0x80028be, 0x34a5f125, 0x34028100, 0xa5020000,
-0x9582000e, 0x800261d, 0xa5020002, 0x8f850100,
-0x27623000, 0x24a60020, 0xc2102b, 0x50400001,
-0x27662800, 0x8f820108, 0x10c20004, 0x0,
-0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a8,
-0x4821, 0x24420001, 0xaee201a8, 0x800260d,
-0x8ee201a8, 0x2c64000c, 0x1441021, 0xaca20000,
-0xaca30004, 0x8ee37264, 0x24e2fff4, 0xa4a2000e,
-0x24020006, 0xaca20018, 0x24630010, 0xaca30008,
-0x8ee204e4, 0xaca2001c, 0x8ee204c8, 0x3c030002,
-0x431025, 0xaca20010, 0xaf860100, 0x92e204ec,
-0x14400037, 0x24090001, 0x8ee24e28, 0x210c0,
-0x24424e38, 0x2e22021, 0x8c830000, 0x24020005,
-0x1462001f, 0x0, 0x8ee34e28, 0x8ee24e2c,
-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001,
-0x10430007, 0x0, 0x8ee24e2c, 0x24420001,
-0x10a20005, 0x0, 0x80025f7, 0x0,
-0x14a00005, 0x0, 0x8f820108, 0x24420020,
-0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011,
-0x50400013, 0xac800000, 0x800260d, 0x0,
-0x8ee24e28, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x24020005, 0xac820000, 0x24020001, 0xac820004,
-0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264,
-0x3c040001, 0x24845730, 0x3c050004, 0xafa20014,
-0x8ee604e4, 0x80028be, 0x34a5f015, 0x8ee37264,
-0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e,
-0x8002681, 0x24e70004, 0x8f840100, 0x27623000,
-0x24850020, 0xa2102b, 0x50400001, 0x27652800,
-0x8f820108, 0x10a20004, 0x0, 0x8f820104,
-0x14a20007, 0x24020006, 0x8ee201a8, 0x4821,
-0x24420001, 0xaee201a8, 0x8002677, 0x8ee201a8,
-0xac8a0000, 0xac8b0004, 0x8ee37264, 0xa487000e,
-0xac820018, 0xac830008, 0x8ee204e4, 0xac82001c,
-0x8ee204c8, 0x3c030002, 0x431025, 0xac820010,
-0xaf850100, 0x92e204ec, 0x14400037, 0x24090001,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x8c830000, 0x24020005, 0x1462001f, 0x0,
-0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
-0x8ee54e28, 0x24420001, 0x10430007, 0x0,
-0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
-0x8002661, 0x0, 0x14a00005, 0x0,
-0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x8002677, 0x0, 0x8ee24e28, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
-0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
-0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
-0x24020001, 0xac820004, 0x15200009, 0x3c050004,
-0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730,
-0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f004,
-0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c,
-0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100,
-0x431021, 0xac44000c, 0x8ee27258, 0xafa20018,
-0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c,
-0x10400004, 0x24620001, 0x2403fffe, 0x431024,
-0xafa2001c, 0x8ee27264, 0x3c060001, 0x34c63800,
-0x8ee3725c, 0x2405fff8, 0x471021, 0x24420007,
-0x451024, 0x24630007, 0xaee27258, 0x8ee2726c,
-0x8ee47258, 0x651824, 0x431023, 0xaee2726c,
-0x3661021, 0x82202b, 0x14800004, 0x3c03ffff,
-0x8ee27258, 0x431021, 0xaee27258, 0x8ee27258,
-0xaee27264, 0x8f8200f0, 0x24470008, 0x27621800,
-0xe2102b, 0x50400001, 0x27671000, 0x8f8200f4,
-0x14e20007, 0x0, 0x8ee201b4, 0x4821,
-0x24420001, 0xaee201b4, 0x80026c4, 0x8ee201b4,
-0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c,
-0xac430000, 0xac440004, 0xaf8700f0, 0x15200012,
-0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4,
-0x3c040001, 0x2484573c, 0xafa20014, 0x8fa60018,
-0x8fa7001c, 0x3c050004, 0xc002403, 0x34a5f005,
-0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088,
-0x80028d3, 0xaee0725c, 0x30430003, 0x24020002,
-0x10620016, 0x28620003, 0x10400005, 0x24020001,
-0x10620008, 0x0, 0x8002703, 0x0,
-0x24020003, 0x10620017, 0x0, 0x8002703,
-0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001,
-0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec,
-0x8ee200e8, 0x8002703, 0x8ee300ec, 0x8ee200f0,
-0x8ee300f4, 0x24630001, 0x2c640001, 0x441021,
-0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002703,
-0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001,
-0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
-0x8ee200f8, 0x8ee300fc, 0x8ee2725c, 0x8ee400e0,
-0x8ee500e4, 0x401821, 0x1021, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0xaee400e0,
-0xaee500e4, 0x80028d3, 0xaee0725c, 0x30e2ffff,
-0x104001c1, 0x31a20200, 0x1040014d, 0x4821,
-0x96e2045a, 0x30420010, 0x10400149, 0x0,
-0x8f840100, 0x27623000, 0x24850020, 0xa2102b,
-0x50400001, 0x27652800, 0x8f820108, 0x10a20004,
-0x0, 0x8f820104, 0x14a20006, 0x2402000c,
-0x8ee201a8, 0x24420001, 0xaee201a8, 0x800276e,
-0x8ee201a8, 0xac8a0000, 0xac8b0004, 0x8ee37264,
-0x24060005, 0xa482000e, 0xac860018, 0xac830008,
-0x8ee204e4, 0xac82001c, 0x8ee204c8, 0xac820010,
-0xaf850100, 0x92e204ec, 0x14400036, 0x24090001,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x8c820000, 0x1446001f, 0x0, 0x8ee34e28,
-0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
-0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
-0x24420001, 0x10a20005, 0x0, 0x8002758,
-0x0, 0x14a00005, 0x0, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x800276e,
-0x0, 0x8ee24e28, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e22021, 0x24020005, 0xac820000, 0x24020001,
-0xac820004, 0x1520000a, 0x3c040001, 0xafab0010,
-0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004,
-0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f014,
-0x8ee27264, 0x34843800, 0x3641821, 0x24420010,
-0x43102b, 0x14400073, 0x0, 0x8ee27264,
-0x24480010, 0x3641021, 0x102102b, 0x14400002,
-0x3c02ffff, 0x1024021, 0x8f850100, 0x27623000,
-0x24a60020, 0xc2102b, 0x50400001, 0x27662800,
-0x8f820108, 0x10c20004, 0x0, 0x8f820104,
-0x14c20007, 0x2563000c, 0x8ee201a8, 0x4821,
-0x24420001, 0xaee201a8, 0x80027e2, 0x8ee201a8,
-0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004,
-0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca80008,
-0xaca20018, 0x8ee204e4, 0xaca2001c, 0x8ee204c8,
-0x3c030002, 0x431025, 0xaca20010, 0xaf860100,
-0x92e204ec, 0x14400037, 0x24090001, 0x8ee24e28,
-0x210c0, 0x24424e38, 0x2e22021, 0x8c830000,
-0x24020005, 0x1462001f, 0x0, 0x8ee34e28,
-0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
-0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
-0x24420001, 0x10a20005, 0x0, 0x80027cc,
-0x0, 0x14a00005, 0x0, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x80027e2,
-0x0, 0x8ee24e28, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e22021, 0x24020005, 0xac820000, 0x24020001,
-0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010,
-0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004,
-0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f015,
-0x34028100, 0xa5020000, 0x9582000e, 0x800285f,
-0xa5020002, 0x8f850100, 0x27623000, 0x24a60020,
-0xc2102b, 0x50400001, 0x27662800, 0x8f820108,
-0x10c20004, 0x0, 0x8f820104, 0x14c20007,
-0x2563000c, 0x8ee201a8, 0x4821, 0x24420001,
-0xaee201a8, 0x800284f, 0x8ee201a8, 0x2c64000c,
-0x1441021, 0xaca20000, 0xaca30004, 0x8ee37264,
-0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca20018,
-0x24630010, 0xaca30008, 0x8ee204e4, 0xaca2001c,
-0x8ee204c8, 0x3c030002, 0x431025, 0xaca20010,
-0xaf860100, 0x92e204ec, 0x14400037, 0x24090001,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x8c830000, 0x24020005, 0x1462001f, 0x0,
-0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
-0x8ee54e28, 0x24420001, 0x10430007, 0x0,
-0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
-0x8002839, 0x0, 0x14a00005, 0x0,
-0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x800284f, 0x0, 0x8ee24e28, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
-0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
-0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
-0x24020001, 0xac820004, 0x1520000a, 0x34028100,
-0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730,
-0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028be,
-0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264,
-0x9582000e, 0xa462000e, 0x80028c2, 0x24e70004,
-0x8f830100, 0x27623000, 0x24640020, 0x82102b,
-0x50400001, 0x27642800, 0x8f820108, 0x10820004,
-0x0, 0x8f820104, 0x14820007, 0x24050005,
-0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8,
-0x80028b6, 0x8ee201a8, 0xac6a0000, 0xac6b0004,
-0x8ee27264, 0xa467000e, 0xac650018, 0xac620008,
-0x8ee204e4, 0xac62001c, 0x8ee204c8, 0xac620010,
-0xaf840100, 0x92e204ec, 0x14400036, 0x24090001,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x8c820000, 0x1445001f, 0x0, 0x8ee34e28,
-0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
-0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
-0x24420001, 0x10a20005, 0x0, 0x80028a0,
-0x0, 0x14a00005, 0x0, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x80028b6,
-0x0, 0x8ee24e28, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e22021, 0x24020005, 0xac820000, 0x24020001,
-0xac820004, 0x1520000b, 0x3c050004, 0x3c040001,
-0x24845748, 0xafab0010, 0xafa00014, 0x8ee604e4,
-0x34a5f017, 0xc002403, 0x30e7ffff, 0x80028e1,
-0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff,
-0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264,
-0x34a53800, 0x441021, 0xaee2725c, 0x3651021,
-0x62182b, 0x14600004, 0x3c03ffff, 0x8ee27264,
-0x431021, 0xaee27264, 0x8ee304e4, 0x96e20458,
-0x24630001, 0x2442ffff, 0x621824, 0xaee304e4,
-0x8ee304e4, 0x8ee204e0, 0x14620005, 0x0,
-0x8f820060, 0x2403fff7, 0x431024, 0xaf820060,
-0x8fbf0020, 0x3e00008, 0x27bd0028, 0x27bdffe0,
-0xafbf0018, 0x8ee304e8, 0x8ee204e0, 0x10620189,
-0x0, 0x8ee204e8, 0x8ee304fc, 0x21100,
-0x621821, 0x94670008, 0x92e204ed, 0x8c680000,
-0x8c690004, 0x10400023, 0x946a000a, 0x8ee204c8,
-0x34460400, 0x31420200, 0x1040001f, 0x0,
-0x96e2045a, 0x30420010, 0x1040001b, 0x3c028000,
-0x3c010001, 0x370821, 0xac2283d8, 0x8ee27264,
-0x9464000e, 0x3c050001, 0x34a53800, 0x24420004,
-0xaee27264, 0x8ee37264, 0x42400, 0x3651021,
-0x3c010001, 0x370821, 0xac2483dc, 0x62182b,
-0x14600005, 0x24e70004, 0x8ee27264, 0x3c03ffff,
-0x431021, 0xaee27264, 0x8ee27264, 0x8002917,
-0xaee27258, 0x8ee604c8, 0x8ee2726c, 0x30e4ffff,
-0x44102a, 0x10400015, 0x0, 0x8f8200d8,
-0x8ee37258, 0x431023, 0xaee2726c, 0x8ee2726c,
-0x1c400007, 0x44102a, 0x8ee2726c, 0x3c030001,
-0x431021, 0xaee2726c, 0x8ee2726c, 0x44102a,
-0x10400006, 0x0, 0x8ee201b8, 0x24420001,
-0xaee201b8, 0x8002a72, 0x8ee201b8, 0x3c020001,
-0x571021, 0x8c4283d8, 0x54400001, 0x24e7fffc,
-0x31420004, 0x104000b9, 0x30e2ffff, 0x3c020001,
-0x571021, 0x8c4283d8, 0x1040002f, 0x5021,
-0x8f840100, 0x27623000, 0x24850020, 0xa2102b,
-0x50400001, 0x27652800, 0x8f820108, 0x10a20032,
-0x0, 0x8f820104, 0x10a2002f, 0x24020015,
-0xac880000, 0xac890004, 0x8ee37264, 0xa487000e,
-0xac820018, 0xac830008, 0x8ee204e8, 0x3c030001,
-0x771821, 0x8c6383dc, 0xac860010, 0x431025,
-0xac82001c, 0xaf850100, 0x92e204ec, 0x14400066,
-0x240a0001, 0x8ee24e28, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e21821, 0x24020015, 0xac620000, 0x24020001,
-0x80029bf, 0xac620004, 0x8f840100, 0x27623000,
-0x24850020, 0xa2102b, 0x50400001, 0x27652800,
-0x8f820108, 0x10a20004, 0x0, 0x8f820104,
-0x14a20006, 0x24020006, 0x8ee201a8, 0x24420001,
-0xaee201a8, 0x80029bf, 0x8ee201a8, 0xac880000,
-0xac890004, 0x8ee37264, 0xa487000e, 0xac820018,
-0xac830008, 0x8ee204e8, 0xac860010, 0xac82001c,
-0xaf850100, 0x92e204ec, 0x14400037, 0x240a0001,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x8c830000, 0x24020005, 0x1462001f, 0x0,
-0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
-0x8ee54e28, 0x24420001, 0x10430007, 0x0,
-0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
-0x80029a9, 0x0, 0x14a00005, 0x0,
-0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x80029bf, 0x0, 0x8ee24e28, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
-0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
-0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
-0x24020001, 0xac820004, 0x1540000a, 0x24020001,
-0xafa90010, 0x8ee27264, 0x3c040001, 0x24845730,
-0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a4f,
-0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc,
-0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001,
-0x370821, 0xac2083d8, 0x3c010001, 0x370821,
-0xac2083dc, 0x21100, 0x431021, 0xac44000c,
-0x8ee27264, 0x2405fff8, 0x30e3ffff, 0x431021,
-0x24420007, 0x451024, 0x24630007, 0xaee27258,
-0x8ee2726c, 0x8ee47258, 0x651824, 0x431023,
-0xaee2726c, 0x3661021, 0x82202b, 0x14800004,
-0x3c03ffff, 0x8ee27258, 0x431021, 0xaee27258,
-0x8ee27258, 0x8002a64, 0xaee27264, 0x10400073,
-0x0, 0x8f830100, 0x27623000, 0x24640020,
-0x82102b, 0x14400002, 0x5021, 0x27642800,
-0x8f820108, 0x10820004, 0x0, 0x8f820104,
-0x14820006, 0x24050005, 0x8ee201a8, 0x24420001,
-0xaee201a8, 0x8002a46, 0x8ee201a8, 0xac680000,
-0xac690004, 0x8ee27264, 0xa467000e, 0xac650018,
-0xac620008, 0x8ee204e8, 0xac660010, 0xac62001c,
-0xaf840100, 0x92e204ec, 0x14400036, 0x240a0001,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x8c820000, 0x1445001f, 0x0, 0x8ee34e28,
-0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
-0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
-0x24420001, 0x10a20005, 0x0, 0x8002a30,
-0x0, 0x14a00005, 0x0, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x8002a46,
-0x0, 0x8ee24e28, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e22021, 0x24020005, 0xac820000, 0x24020001,
-0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001,
-0x24845748, 0x3c050004, 0xafa90010, 0xafa00014,
-0x8ee604e4, 0x34a5f237, 0xc002403, 0x30e7ffff,
-0x8002a72, 0x0, 0x8ee27264, 0x451021,
-0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001,
-0x34843800, 0xa2e004ed, 0x451023, 0xaee2726c,
-0x3641021, 0x62182b, 0x14600004, 0x3c03ffff,
-0x8ee27264, 0x431021, 0xaee27264, 0x8ee304e8,
-0x96e20458, 0x24630001, 0x2442ffff, 0x621824,
-0xaee304e8, 0x8ee304e8, 0x8ee204e0, 0x14620005,
-0x0, 0x8f820060, 0x2403fff7, 0x431024,
-0xaf820060, 0x8fbf0018, 0x3e00008, 0x27bd0020,
-0x27bdffe0, 0xafbf001c, 0xafb00018, 0x8f820100,
-0x8ee34e2c, 0x8f820104, 0x8f850108, 0x24020040,
-0x24630001, 0x50620003, 0x1021, 0x8ee24e2c,
-0x24420001, 0xaee24e2c, 0x8ee24e2c, 0x8ee34e2c,
-0x210c0, 0x24424e38, 0x2e22021, 0x8ee24e28,
-0x8c870004, 0x14620007, 0xa03021, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x8002aa2,
-0xac800000, 0x8ee24e2c, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e2c, 0x24420001,
-0x210c0, 0x24424e38, 0x2e22021, 0x8c820004,
-0x8f830108, 0x21140, 0x621821, 0xaf830108,
-0xac800000, 0x8cc20018, 0x2443fffe, 0x2c620013,
-0x104000c1, 0x31080, 0x3c010001, 0x220821,
-0x8c225770, 0x400008, 0x0, 0x8ee204f0,
-0x471021, 0xaee204f0, 0x8ee204f0, 0x8f43023c,
-0x43102b, 0x144000be, 0x0, 0x8ee304e4,
-0x8ee204f8, 0x506200ba, 0xa2e004f4, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x8021, 0x24420001, 0xaee201a4, 0x8002b12,
-0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0,
-0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008,
-0xa462000e, 0x24020011, 0xac620018, 0xac640000,
-0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
-0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
-0x24420001, 0x10430007, 0x0, 0x8ee24e34,
-0x24420001, 0x10a20005, 0x0, 0x8002afc,
-0x0, 0x14a00005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x8002b12,
-0x0, 0x8ee24e30, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x24020012, 0xac820000, 0x24020001,
-0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4,
-0x3c040001, 0x24845754, 0xafa00014, 0xafa20010,
-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
-0x34a5f006, 0x16000003, 0x24020001, 0x8002b71,
-0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170,
-0x8ee20170, 0x8ee204e4, 0xa2e004f4, 0xaee004f0,
-0xaee204f8, 0x8f42023c, 0x50400045, 0xaee07274,
-0x8ee20184, 0x24420001, 0xaee20184, 0x8ee20184,
-0x8002b71, 0xaee07274, 0x8ee20504, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee20504,
-0x24420001, 0xaee20504, 0x8ee20504, 0x8cc30018,
-0x21080, 0x571021, 0x8c440508, 0x24020003,
-0x1462000f, 0x0, 0x3c020001, 0x571021,
-0x904283b1, 0x10400014, 0x0, 0x8ee201d0,
-0x8ee35240, 0x441021, 0xaee201d0, 0x8ee201d8,
-0x641821, 0x306300ff, 0x8002b59, 0xaee35240,
-0x8ee201cc, 0x8ee30e10, 0x441021, 0xaee201cc,
-0x8ee201d8, 0x641821, 0x306301ff, 0xaee30e10,
-0x441021, 0xaee201d8, 0x8ee20000, 0x34420040,
-0x8002b71, 0xaee20000, 0x8ee2014c, 0x3c010001,
-0x370821, 0xa02083e0, 0x24420001, 0xaee2014c,
-0x8002b71, 0x8ee2014c, 0x94c7000e, 0x8cc2001c,
-0x3c040001, 0x24845760, 0xafa60014, 0xafa20010,
-0x8cc60018, 0x3c050008, 0xc002403, 0x34a50910,
-0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
-0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058,
-0xafb50054, 0xafb40050, 0xafb3004c, 0xafb20048,
-0xafb10044, 0xafb00040, 0x8f830108, 0x8f820104,
-0xafa00024, 0x106203e7, 0xafa0002c, 0x3c1e0001,
-0x37de3800, 0x3c0bffff, 0x8f930108, 0x8e620018,
-0x8f830104, 0x2443fffe, 0x2c620014, 0x104003cf,
-0x31080, 0x3c010001, 0x220821, 0x8c2257c0,
-0x400008, 0x0, 0x9663000e, 0x8ee2725c,
-0x8ee404f0, 0x431021, 0xaee2725c, 0x8e63001c,
-0x96e20458, 0x24840001, 0xaee404f0, 0x24630001,
-0x2442ffff, 0x621824, 0xaee304e4, 0x8f42023c,
-0x82202b, 0x148003b9, 0x0, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x8021, 0x24420001, 0xaee201a4, 0x8002bfe,
-0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0,
-0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008,
-0xa462000e, 0x24020011, 0xac620018, 0xac640000,
-0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
-0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x240c0040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x8002be8,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x8002bfe,
-0x0, 0x8ee24e30, 0x240c0040, 0x24420001,
-0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x24020012, 0x240c0001, 0xac820000,
-0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4,
-0x3c040001, 0x24845754, 0xafa00014, 0xafa20010,
-0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006,
-0xc002403, 0xafab0038, 0x8fab0038, 0x1200030a,
-0x240c0001, 0x8002f19, 0x0, 0x966c001c,
-0xafac002c, 0x9662001e, 0x3c0c8000, 0xafac0024,
-0xae62001c, 0x8e75001c, 0x8ee204fc, 0x8ee404fc,
-0x151900, 0x621021, 0x8c52000c, 0x92e27b98,
-0x641821, 0x9476000a, 0x14400003, 0x32c20002,
-0xaef27ba4, 0xaef57b9c, 0x1040004b, 0x8021,
-0x96e2045a, 0x30420002, 0x10400047, 0x0,
-0x8e63001c, 0x8ee204fc, 0x32100, 0x821021,
-0x8c42000c, 0x37e1821, 0x24420022, 0x43102b,
-0x1440000a, 0x24050014, 0x8ee204fc, 0x821021,
-0x8c44000c, 0xafab0038, 0xc002f75, 0x2484000e,
-0x8fab0038, 0x8002c52, 0x3050ffff, 0x8ee204fc,
-0x821021, 0x8c42000c, 0x9450000e, 0x94430010,
-0x94440012, 0x94450014, 0x2038021, 0x2048021,
-0x2058021, 0x94430016, 0x94440018, 0x9445001a,
-0x2038021, 0x2048021, 0x2058021, 0x9443001c,
-0x9444001e, 0x94420020, 0x2038021, 0x2048021,
-0x2028021, 0x101c02, 0x3202ffff, 0x628021,
-0x8e63001c, 0x8ee204fc, 0x102402, 0x32900,
-0xa21021, 0x8c43000c, 0x3202ffff, 0x828021,
-0x37e1021, 0x24630018, 0x62182b, 0x14600009,
-0x0, 0x8ee204fc, 0xa21021, 0x8c43000c,
-0x101027, 0x3c01ffff, 0x230821, 0x8002c6f,
-0xa4220018, 0x8ee204fc, 0xa21021, 0x8c43000c,
-0x101027, 0xa4620018, 0x96e2045a, 0x8821,
-0x30420008, 0x14400063, 0xa021, 0x8e63001c,
-0x8ee204fc, 0x33100, 0xc21021, 0x8c42000c,
-0x37e1821, 0x24420022, 0x43102b, 0x14400035,
-0x0, 0x8ee204fc, 0xc21021, 0x8c42000c,
-0x24470010, 0x37e1021, 0xe2102b, 0x50400001,
-0xeb3821, 0x8ee204fc, 0x94f10000, 0xc21021,
-0x8c42000c, 0x24470016, 0x37e1021, 0xe2102b,
-0x14400002, 0x2634ffec, 0xeb3821, 0x8ee204fc,
-0x90e30001, 0xc21021, 0x8c42000c, 0x2447001a,
-0x37e1021, 0xe2102b, 0x14400002, 0x2838821,
-0xeb3821, 0x94e20000, 0x24e70002, 0x2228821,
-0x37e1021, 0xe2102b, 0x50400001, 0xeb3821,
-0x94e20000, 0x24e70002, 0x2228821, 0x37e1021,
-0xe2102b, 0x50400001, 0xeb3821, 0x94e20000,
-0x24e70002, 0x2228821, 0x37e1021, 0xe2102b,
-0x50400001, 0xeb3821, 0x94e20000, 0x8002cd0,
-0x2228821, 0x8ee204fc, 0xc21021, 0x8c43000c,
-0x8ee204fc, 0x94710010, 0x8ee304fc, 0xc21021,
-0x8c44000c, 0xc31821, 0x8c62000c, 0x2634ffec,
-0x90840017, 0x8ee304fc, 0x9442001a, 0x2848821,
-0xc31821, 0x8c65000c, 0x8ee304fc, 0x2228821,
-0x8ee204fc, 0xc31821, 0xc21021, 0x8c44000c,
-0x8c62000c, 0x94a3001c, 0x9484001e, 0x94420020,
-0x2238821, 0x2248821, 0x2228821, 0x111c02,
-0x3222ffff, 0x628821, 0x111c02, 0x3222ffff,
-0x628821, 0x32c20001, 0x104000b2, 0x0,
-0x96e2045a, 0x30420001, 0x104000ae, 0x32c20080,
-0x10400008, 0x0, 0x92e27b98, 0x14400005,
-0x0, 0x240c0001, 0xa2ec7b98, 0xaef57b9c,
-0xaef27ba4, 0x8ee304fc, 0x151100, 0x431021,
-0x8c47000c, 0x37e1821, 0x24e2000e, 0x43102b,
-0x14400008, 0xe02021, 0x2405000e, 0xc002f75,
-0xafab0038, 0x3042ffff, 0x8fab0038, 0x8002d09,
-0x2028021, 0x94e60000, 0x24e70002, 0x94e50000,
-0x24e70002, 0x94e30000, 0x24e70002, 0x94e20000,
-0x24e70002, 0x94e40000, 0x24e70002, 0x2068021,
-0x2058021, 0x2038021, 0x2028021, 0x94e20000,
-0x94e30002, 0x2048021, 0x2028021, 0x2038021,
-0x101c02, 0x3202ffff, 0x628021, 0x101c02,
-0x3202ffff, 0x8ee47b9c, 0x628021, 0x14950004,
-0x3205ffff, 0x96620016, 0x8002d17, 0x512021,
-0x96620016, 0x542021, 0x41402, 0x3083ffff,
-0x432021, 0x852023, 0x41402, 0x822021,
-0x3084ffff, 0x50800001, 0x3404ffff, 0x8ee27ba4,
-0x24430017, 0x37e1021, 0x62102b, 0x50400001,
-0x6b1821, 0x90630000, 0x24020011, 0x14620031,
-0x24020006, 0x8ee27ba4, 0x37e1821, 0x24420028,
-0x43102b, 0x14400018, 0x0, 0x8ee27b9c,
-0x12a2000a, 0x32c20100, 0x8ee27ba4, 0x3c01ffff,
-0x220821, 0x94220028, 0x822021, 0x41c02,
-0x3082ffff, 0x622021, 0x32c20100, 0x14400004,
-0x41027, 0x92e27b98, 0x14400002, 0x41027,
-0x3044ffff, 0x8ee27ba4, 0x3c01ffff, 0x220821,
-0x8002d8a, 0xa4240028, 0x8ee27b9c, 0x12a20008,
-0x32c20100, 0x8ee27ba4, 0x94420028, 0x822021,
-0x41c02, 0x3082ffff, 0x622021, 0x32c20100,
-0x14400004, 0x41027, 0x92e27b98, 0x14400002,
-0x41027, 0x3044ffff, 0x8ee27ba4, 0x8002d8a,
-0xa4440028, 0x1462002f, 0x37e1821, 0x8ee27ba4,
-0x24420032, 0x43102b, 0x14400018, 0x0,
-0x8ee27b9c, 0x12a2000a, 0x32c20100, 0x8ee27ba4,
-0x3c01ffff, 0x220821, 0x94220032, 0x822021,
-0x41c02, 0x3082ffff, 0x622021, 0x32c20100,
-0x14400004, 0x41027, 0x92e27b98, 0x14400002,
-0x41027, 0x3044ffff, 0x8ee27ba4, 0x3c01ffff,
-0x220821, 0x8002d8a, 0xa4240032, 0x8ee27b9c,
-0x12a20008, 0x32c20100, 0x8ee27ba4, 0x94420032,
-0x822021, 0x41c02, 0x3082ffff, 0x622021,
-0x32c20100, 0x14400004, 0x41027, 0x92e27b98,
-0x14400002, 0x41027, 0x3044ffff, 0x8ee27ba4,
-0xa4440032, 0x8fac0024, 0x1180002c, 0x37e1821,
-0x8e420000, 0xae42fffc, 0x2642000a, 0x43102b,
-0x1440001b, 0x34038100, 0x26430004, 0x37e1021,
-0x62102b, 0x14400003, 0x602021, 0x6b1821,
-0x602021, 0x8c620000, 0x24630004, 0xae420000,
-0x37e1021, 0x62102b, 0x50400001, 0x6b1821,
-0x8c620000, 0xac820000, 0x34028100, 0xa4620000,
-0x24630002, 0x37e1021, 0x62102b, 0x50400001,
-0x6b1821, 0x97ac002e, 0x8002db4, 0xa46c0000,
-0x8e420004, 0x8e440008, 0xa6430008, 0x97ac002e,
-0xa64c000a, 0xae420000, 0xae440004, 0x9662000e,
-0x2652fffc, 0x24420004, 0xa662000e, 0x9662000e,
-0x8ee3725c, 0x621821, 0xaee3725c, 0xafb20018,
-0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c,
-0x10400004, 0x24620001, 0x2403fffe, 0x431024,
-0xafa2001c, 0x32c20080, 0x1040000c, 0x32c20100,
-0x8ee27ba8, 0x24430001, 0x210c0, 0x571021,
-0xaee37ba8, 0x8fa30018, 0x8fa4001c, 0xac437bac,
-0xac447bb0, 0x8002ea0, 0xaee0725c, 0x10400072,
-0x0, 0x8ee27ba8, 0x24430001, 0x210c0,
-0x571021, 0xaee37ba8, 0x8fa30018, 0x8fa4001c,
-0xac437bac, 0xac447bb0, 0x8ee27ba8, 0x10400063,
-0x4821, 0x5021, 0x8f8200f0, 0x24480008,
-0x27621800, 0x102102b, 0x50400001, 0x27681000,
-0x8f8200f4, 0x15020007, 0x0, 0x8ee201b4,
-0x8021, 0x24420001, 0xaee201b4, 0x8002dfa,
-0x8ee201b4, 0x8f8300f0, 0x24100001, 0x1571021,
-0x8c447bac, 0x8c457bb0, 0xac640000, 0xac650004,
-0xaf8800f0, 0x16000006, 0x2ea1021, 0x8ee20088,
-0x24420001, 0xaee20088, 0x8002e3f, 0x8ee20088,
-0x8c427bb0, 0x8ee400e0, 0x8ee500e4, 0x8ee67b9c,
-0x401821, 0x1021, 0xa32821, 0xa3382b,
-0x822021, 0x872021, 0x8ee204fc, 0xc93021,
-0x63100, 0xaee400e0, 0xaee500e4, 0xc23021,
-0x94c2000a, 0x240c0002, 0x21142, 0x30430003,
-0x106c0016, 0x28620003, 0x10400005, 0x240c0001,
-0x106c0008, 0x0, 0x8002e3f, 0x0,
-0x240c0003, 0x106c0017, 0x0, 0x8002e3f,
-0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001,
-0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec,
-0x8ee200e8, 0x8002e3f, 0x8ee300ec, 0x8ee200f0,
-0x8ee300f4, 0x24630001, 0x2c640001, 0x441021,
-0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002e3f,
-0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001,
-0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
-0x8ee200f8, 0x8ee300fc, 0x8ee27ba8, 0x25290001,
-0x122102b, 0x1440ffa0, 0x254a0008, 0xa2e07b98,
-0x8002e9f, 0xaee07ba8, 0x8f8200f0, 0x24470008,
-0x27621800, 0xe2102b, 0x50400001, 0x27671000,
-0x8f8200f4, 0x14e20007, 0x0, 0x8ee201b4,
-0x8021, 0x24420001, 0xaee201b4, 0x8002e5d,
-0x8ee201b4, 0x8f8200f0, 0x24100001, 0x8fa30018,
-0x8fa4001c, 0xac430000, 0xac440004, 0xaf8700f0,
-0x16000007, 0x0, 0x8ee20088, 0x24420001,
-0xaee20088, 0x8ee20088, 0x8002ea0, 0xaee0725c,
-0x8ee2725c, 0x8ee400e0, 0x8ee500e4, 0x240c0002,
-0x401821, 0x1021, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0x161142, 0x30430003,
-0xaee400e0, 0xaee500e4, 0x106c0017, 0x2c620003,
-0x10400005, 0x240c0001, 0x106c0008, 0x0,
-0x8002ea0, 0xaee0725c, 0x240c0003, 0x106c0019,
-0x0, 0x8002ea0, 0xaee0725c, 0x8ee200e8,
-0x8ee300ec, 0x24630001, 0x2c640001, 0x441021,
-0xaee200e8, 0xaee300ec, 0x8ee200e8, 0x8ee300ec,
-0x8002ea0, 0xaee0725c, 0x8ee200f0, 0x8ee300f4,
-0x24630001, 0x2c640001, 0x441021, 0xaee200f0,
-0xaee300f4, 0x8ee200f0, 0x8ee300f4, 0x8002ea0,
-0xaee0725c, 0x8ee200f8, 0x8ee300fc, 0x24630001,
-0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
-0x8ee200f8, 0x8ee300fc, 0xaee0725c, 0x8e62001c,
-0x96e30458, 0x8ee404f0, 0x24420001, 0x2463ffff,
-0x431024, 0x24840001, 0xaee204e4, 0xaee404f0,
-0x8f42023c, 0x82202b, 0x148000b0, 0x0,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
-0x8002f07, 0x8ee201a4, 0x8ee204e4, 0xac62001c,
-0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008,
-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400037, 0x24100001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c830000, 0x24020012, 0x1462001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x240c0040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
-0x8002ef1, 0x0, 0x14600005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x8002f07, 0x0, 0x8ee24e30, 0x240c0040,
-0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020012, 0x240c0001,
-0xac820000, 0xac8c0004, 0x5600000d, 0x24100001,
-0x8ee204e4, 0x3c040001, 0x24845754, 0xafa00014,
-0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
-0x34a5f006, 0xc002403, 0xafab0038, 0x8fab0038,
-0x16000003, 0x240c0001, 0x8002f5c, 0xa2ec04f4,
-0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170,
-0x8ee204e4, 0xa2e004f4, 0xaee004f0, 0xaee07274,
-0xaee204f8, 0x8f42023c, 0x10400038, 0x0,
-0x8ee20184, 0x24420001, 0xaee20184, 0x8002f5c,
-0x8ee20184, 0x8ee20504, 0x240c0040, 0x24420001,
-0x504c0003, 0x1021, 0x8ee20504, 0x24420001,
-0xaee20504, 0x8ee20504, 0x8e630018, 0x240c0003,
-0x21080, 0x571021, 0x146c000f, 0x8c440508,
-0x3c020001, 0x571021, 0x904283b1, 0x10400014,
-0x0, 0x8ee201d0, 0x8ee35240, 0x441021,
-0xaee201d0, 0x8ee201d8, 0x641821, 0x306300ff,
-0x8002f4f, 0xaee35240, 0x8ee201cc, 0x8ee30e10,
-0x441021, 0xaee201cc, 0x8ee201d8, 0x641821,
-0x306301ff, 0xaee30e10, 0x441021, 0xaee201d8,
-0x8ee20000, 0x34420040, 0x8002f5c, 0xaee20000,
-0x8ee2014c, 0x3c010001, 0x370821, 0xa02083e0,
-0x24420001, 0xaee2014c, 0x8ee2014c, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x8f820108,
-0x27633000, 0x43102b, 0x14400002, 0x27622800,
-0xaf820108, 0x8f830108, 0x8f820104, 0x1462fc1e,
-0x0, 0x8fbf0060, 0x8fbe005c, 0x8fb60058,
-0x8fb50054, 0x8fb40050, 0x8fb3004c, 0x8fb20048,
-0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0068,
-0x52843, 0x10a0000d, 0x3021, 0x3c030001,
-0x34633800, 0x3c07ffff, 0x3631021, 0x82102b,
-0x50400001, 0x872021, 0x94820000, 0x24840002,
-0x24a5ffff, 0x14a0fff8, 0xc23021, 0x61c02,
-0x30c2ffff, 0x623021, 0x61c02, 0x30c2ffff,
-0x623021, 0x3e00008, 0x30c2ffff, 0x27bdff88,
-0x240f0001, 0xafbf0070, 0xafbe006c, 0xafb60068,
-0xafb50064, 0xafb40060, 0xafb3005c, 0xafb20058,
-0xafb10054, 0xafb00050, 0xa3a00027, 0xafaf002c,
-0x8ee204d4, 0x8021, 0x30420001, 0x1440002a,
-0xa3a00037, 0x8f8700e0, 0x8f8800c4, 0x8f8200e8,
-0xe22023, 0x2c821000, 0x50400001, 0x24841000,
-0x420c2, 0x801821, 0x8ee400c8, 0x8ee500cc,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaee400c8, 0xaee500cc, 0x8f8300c8,
-0x3c02000a, 0x3442efff, 0x1032023, 0x44102b,
-0x10400003, 0x3c02000a, 0x3442f000, 0x822021,
-0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021,
-0xa32821, 0xa3302b, 0x822021, 0x862021,
-0xaee400c0, 0xaee500c4, 0xaf8800c8, 0xaf8700e4,
-0x80034cc, 0xaf8700e8, 0x3c020001, 0x571021,
-0x904283c0, 0x1040000b, 0x0, 0x3c140001,
-0x297a021, 0x8e9483c4, 0x3c130001, 0x2779821,
-0x8e7383c8, 0x3c120001, 0x2579021, 0x8003193,
-0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 0x10430007,
-0x8821, 0x8f8200e4, 0x24110001, 0x8c430000,
-0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e,
-0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8,
-0x3c040001, 0x24845870, 0xafa20014, 0x8f8600e0,
-0x8f8700e4, 0x3c050006, 0xc002403, 0x34a5f000,
-0x80034cc, 0x0, 0x8fa3001c, 0x8fb20018,
-0x3074ffff, 0x2694fffc, 0x621024, 0x10400058,
-0x2409821, 0x3c020080, 0x621024, 0x1040000a,
-0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c,
-0x8ee2007c, 0x8ee201fc, 0x24420001, 0xaee201fc,
-0x80034c6, 0x8ee201fc, 0x3c060004, 0x3c0b0001,
-0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080,
-0x3c080020, 0x34078000, 0x24420001, 0xaee20080,
-0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021,
-0xc3102b, 0x14400007, 0x0, 0x106b0011,
-0x0, 0x106a0015, 0x0, 0x8003049,
-0x42042, 0x10650023, 0xa3102b, 0x14400005,
-0x0, 0x10690019, 0x0, 0x8003049,
-0x42042, 0x10680021, 0x0, 0x8003049,
-0x42042, 0x8ee20034, 0x24420001, 0xaee20034,
-0x8ee20034, 0x8003049, 0x42042, 0x8ee201ec,
-0x24420001, 0xaee201ec, 0x8ee201ec, 0x8003049,
-0x42042, 0x8ee201f0, 0x24420001, 0xaee201f0,
-0x8ee201f0, 0x8003049, 0x42042, 0x8ee201f4,
-0x24420001, 0xaee201f4, 0x8ee201f4, 0x8003049,
-0x42042, 0x8ee20030, 0x24420001, 0xaee20030,
-0x8ee20030, 0x8003049, 0x42042, 0x8ee201f8,
-0x24420001, 0xaee201f8, 0x8ee201f8, 0x42042,
-0x1087047c, 0x0, 0x800300e, 0x0,
-0x3c020001, 0x571021, 0x904283b2, 0x14400084,
-0x24020001, 0x3c030001, 0x771821, 0x906383b3,
-0x1462007f, 0x3c020100, 0x8e430000, 0x621024,
-0x1040006f, 0x2402ffff, 0x14620005, 0x24100001,
-0x96430004, 0x3402ffff, 0x10620075, 0x0,
-0x92e204d8, 0x14400072, 0x0, 0x3c020001,
-0x571021, 0x8c4283b4, 0x28420005, 0x10400020,
-0x3821, 0x3c020001, 0x571021, 0x8c4283b4,
-0x18400016, 0x2821, 0x96660000, 0x520c0,
-0x971021, 0x9442777e, 0x14460009, 0x971021,
-0x94437780, 0x96620002, 0x14620005, 0x971021,
-0x94437782, 0x96620004, 0x50620008, 0x24070001,
-0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001,
-0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff,
-0x10400440, 0x0, 0x80030d5, 0x0,
-0x2402021, 0xc0022fe, 0x24050006, 0x3044001f,
-0x428c0, 0x2e51021, 0x9442727c, 0x30424000,
-0x14400434, 0xb71021, 0x9443727e, 0x96620000,
-0x1462000b, 0x418c0, 0xb71021, 0x94437280,
-0x96620002, 0x14620006, 0x418c0, 0xb71021,
-0x94437282, 0x96620004, 0x10620035, 0x418c0,
-0x2e31021, 0x9442727c, 0x30428000, 0x14400421,
-0x2e31021, 0x944b727c, 0x96670000, 0xb28c0,
-0xb71021, 0x9442737e, 0x80030b7, 0x3021,
-0x420c0, 0x2e41021, 0x9443737c, 0x2e41021,
-0x944b737c, 0x30638000, 0x14600010, 0xb28c0,
-0xb71021, 0x9442737e, 0x1447fff5, 0x1602021,
-0xb71021, 0x94437380, 0x96620002, 0x5462fff1,
-0x420c0, 0xb71021, 0x94437382, 0x96620004,
-0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff,
-0x10400400, 0x0, 0x80030d5, 0x0,
-0x97430202, 0x96420000, 0x146203fa, 0x0,
-0x97430204, 0x96420002, 0x146203f6, 0x0,
-0x97430206, 0x96420004, 0x146203f2, 0x0,
-0x92420000, 0x3a030001, 0x30420001, 0x431024,
-0x10400074, 0x2402ffff, 0x8e630000, 0x14620004,
-0x3402ffff, 0x96630004, 0x1062006f, 0x240f0002,
-0x3c020001, 0x571021, 0x904283b2, 0x1440006a,
-0x240f0003, 0x92e204d8, 0x54400068, 0xafaf002c,
-0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
-0x10400020, 0x3821, 0x3c020001, 0x571021,
-0x8c4283b4, 0x18400016, 0x2821, 0x96660000,
-0x520c0, 0x971021, 0x9442777e, 0x14460009,
-0x971021, 0x94437780, 0x96620002, 0x14620005,
-0x971021, 0x94437782, 0x96620004, 0x50620008,
-0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
-0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
-0x30e200ff, 0x14400044, 0x240f0003, 0x80034c6,
-0x0, 0x2402021, 0xc0022fe, 0x24050006,
-0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
-0x30424000, 0x144003af, 0xb71021, 0x9443727e,
-0x96620000, 0x1462000b, 0x418c0, 0xb71021,
-0x94437280, 0x96620002, 0x14620006, 0x418c0,
-0xb71021, 0x94437282, 0x96620004, 0x10620027,
-0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
-0x1440039c, 0x2e31021, 0x944b727c, 0x96670000,
-0xb28c0, 0xb71021, 0x9442737e, 0x800313c,
-0x3021, 0x420c0, 0x2e41021, 0x9443737c,
-0x2e41021, 0x944b737c, 0x30638000, 0x14600010,
-0xb28c0, 0xb71021, 0x9442737e, 0x1447fff5,
-0x1602021, 0xb71021, 0x94437380, 0x96620002,
-0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
-0x96620004, 0x5462ffec, 0x420c0, 0x24060001,
-0x30c200ff, 0x1040037b, 0x0, 0x800314f,
-0x240f0003, 0x240f0001, 0xafaf002c, 0x8f420260,
-0x54102b, 0x1040003a, 0x0, 0x8f8300e4,
-0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
-0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2801821,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
-0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
-0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
-0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878,
-0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
-0xc002403, 0x34a5f003, 0x80034cc, 0x0,
-0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
-0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
-0x3c050006, 0xc002403, 0x34a5f002, 0x8ee201c0,
-0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0,
-0x2403ffbf, 0x431024, 0x8003470, 0xaee20000,
-0x96e20468, 0x54102b, 0x10400003, 0x0,
-0x240f0001, 0xa3af0027, 0x12800301, 0x24160007,
-0x24150040, 0x241e0001, 0x240e0012, 0x8ee2724c,
-0x8f430280, 0x24420001, 0x304207ff, 0x106202d3,
-0x0, 0x93a20027, 0x10400014, 0x0,
-0x8ee35240, 0x8ee25244, 0x10620009, 0x26ed5244,
-0x8ee65244, 0x8ee35244, 0x21140, 0x24425248,
-0x2e28021, 0x24630001, 0x80031bf, 0x306b00ff,
-0x92e27248, 0x1440ffca, 0x0, 0x8ee201e0,
-0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10,
-0x8ee20e18, 0x1062ffc2, 0x26ed0e18, 0x8ee60e18,
-0x8ee30e18, 0x21140, 0x24420e20, 0x2e28021,
-0x24630001, 0x306b01ff, 0x96e2046a, 0x30420010,
-0x10400019, 0x0, 0x9642000c, 0x340f8100,
-0x144f0015, 0x0, 0x3c020001, 0x571021,
-0x904283c0, 0x14400010, 0x0, 0x9642000e,
-0xa6020016, 0x8e420008, 0x8e430004, 0x8e440000,
-0x2694fffc, 0xae42000c, 0xae430008, 0xae440004,
-0x9602000e, 0x26730004, 0x240f0001, 0xa3af0037,
-0x34420200, 0xa602000e, 0x8e020000, 0x8e030004,
-0x3c040001, 0x34843800, 0x306a0007, 0x26a9823,
-0x3641021, 0x262102b, 0x10400005, 0x28aa021,
-0x2641023, 0x3621823, 0x3c020020, 0x439823,
-0x26820007, 0x2404fff8, 0x9603000a, 0x446024,
-0x6a1821, 0x6c102b, 0x10400002, 0x1803821,
-0x603821, 0xae130018, 0x8f880120, 0x24e20007,
-0x443824, 0x27623800, 0x25090020, 0x122102b,
-0x50400001, 0x27693000, 0x8f820128, 0x11220004,
-0x0, 0x8f820124, 0x15220007, 0x1401821,
-0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4,
-0x800324c, 0x8ee201a4, 0x8e040000, 0x8e050004,
-0x1021, 0xad130008, 0xa507000e, 0xad160018,
-0xad06001c, 0xa3302b, 0xa32823, 0x822023,
-0x862023, 0xad040000, 0xad050004, 0x8ee204c0,
-0xad020010, 0xaf890120, 0x92e24e20, 0x14400033,
-0x24110001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c820000, 0x1456001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x10550007, 0x0,
-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
-0x8003239, 0x0, 0x14600005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
-0x800324c, 0x0, 0x8ee24e30, 0x24420001,
-0x50550003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0xac960000, 0xac9e0004, 0x16200018,
-0x3c050006, 0x8e020018, 0x3c040001, 0x24845890,
-0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009,
-0x2003021, 0xc002403, 0xafa30014, 0x93a20037,
-0x10400216, 0x340f8100, 0x8e420004, 0x8e430008,
-0x8e44000c, 0xa64f000c, 0xae420000, 0xae430004,
-0xae440008, 0x96020016, 0x8003470, 0xa642000e,
-0x14ec0168, 0x28a1823, 0x960c000a, 0x9603000e,
-0x28a1023, 0xa602000a, 0x34620004, 0xa602000e,
-0x8f880120, 0x27623800, 0x25090020, 0x122102b,
-0x14400002, 0x306affff, 0x27693000, 0x8f820128,
-0x11220004, 0x0, 0x8f820124, 0x15220007,
-0x24040020, 0x8ee201a4, 0x8821, 0x24420001,
-0xaee201a4, 0x80032ca, 0x8ee201a4, 0x8ee5724c,
-0x8ee60490, 0x8ee70494, 0xa504000e, 0x24040004,
-0xad100008, 0xad040018, 0x52940, 0xa01821,
-0x1021, 0xe33821, 0xe3202b, 0xc23021,
-0xc43021, 0xad060000, 0xad070004, 0x8ee2724c,
-0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120,
-0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c820000,
-0x1456001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x0, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001,
-0x10550007, 0x0, 0x8ee24e34, 0x24420001,
-0x10620005, 0x0, 0x80032b7, 0x0,
-0x14600005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400010, 0xac800000, 0x80032ca, 0x0,
-0x8ee24e30, 0x24420001, 0x50550003, 0x1021,
-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0xac960000,
-0xac9e0004, 0x1620000d, 0x0, 0xa60c000a,
-0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104,
-0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014,
-0x8ee6724c, 0x800343b, 0x34a5f00b, 0x3c010001,
-0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8,
-0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8,
-0x24630001, 0x306307ff, 0x26e25244, 0x15a20006,
-0xaee3724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0,
-0x80032ef, 0x8ee201d0, 0x8ee201cc, 0x2442ffff,
-0xaee201cc, 0x8ee201cc, 0x8f420240, 0x10400073,
-0x0, 0x8ee20e1c, 0x24420001, 0xaee20e1c,
-0x8f430240, 0x43102b, 0x14400176, 0xa021,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4,
-0x800334f, 0x8ee201a4, 0x8ee2724c, 0xac62001c,
-0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008,
-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400033, 0x24110001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x144e001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x10550007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x800333c,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400010, 0xac800000, 0x800334f,
-0x0, 0x8ee24e30, 0x24420001, 0x50550003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001,
-0x8ee2724c, 0x3c040001, 0x248458a8, 0xafa00014,
-0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009,
-0x34a5f008, 0xc002403, 0xafae0048, 0x8fae0048,
-0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001,
-0xaee20188, 0x80033c8, 0x8ee20188, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x8821, 0x24420001, 0xaee201a4, 0x80033ba,
-0x8ee201a4, 0x8ee2724c, 0xac62001c, 0x8ee404a8,
-0x8ee504ac, 0x2462001c, 0xac620008, 0x24020008,
-0xa462000e, 0x24020011, 0xac620018, 0xac640000,
-0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
-0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c820000,
-0x144e001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x0, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001,
-0x10550007, 0x0, 0x8ee24e34, 0x24420001,
-0x10620005, 0x0, 0x80033a7, 0x0,
-0x14600005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400010, 0xac800000, 0x80033ba, 0x0,
-0x8ee24e30, 0x24420001, 0x50550003, 0x1021,
-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0xac8e0000,
-0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c,
-0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010,
-0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008,
-0xc002403, 0xafae0048, 0x8fae0048, 0x8ee20174,
-0x24420001, 0xaee20174, 0x8ee20174, 0x800346e,
-0xa021, 0x960c000a, 0x183102b, 0x54400001,
-0x1801821, 0xa603000a, 0x8f880120, 0x27623800,
-0x25090020, 0x122102b, 0x50400001, 0x27693000,
-0x8f820128, 0x11220004, 0x0, 0x8f820124,
-0x15220007, 0x24040020, 0x8ee201a4, 0x8821,
-0x24420001, 0xaee201a4, 0x800342f, 0x8ee201a4,
-0x8ee5724c, 0x8ee60490, 0x8ee70494, 0xa504000e,
-0x24040004, 0xad100008, 0xad040018, 0x52940,
-0xa01821, 0x1021, 0xe33821, 0xe3202b,
-0xc23021, 0xc43021, 0xad060000, 0xad070004,
-0x8ee2724c, 0xad02001c, 0x8ee204c4, 0xad020010,
-0xaf890120, 0x92e24e20, 0x14400033, 0x24110001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x1456001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x10550007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x800341c,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400010, 0xac800000, 0x800342f,
-0x0, 0x8ee24e30, 0x24420001, 0x50550003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0xac960000, 0xac9e0004, 0x1620001d, 0x0,
-0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104,
-0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014,
-0x8ee6724c, 0x34a5f00d, 0xc002403, 0x2003821,
-0x93a20037, 0x10400031, 0x340f8100, 0x8e420004,
-0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000,
-0xae430004, 0xae440008, 0x96020016, 0xa642000e,
-0x9602000e, 0x3042fdff, 0x8003470, 0xa602000e,
-0x8ee201d8, 0x2442ffff, 0xaee201d8, 0x8ee201d8,
-0x8ee201cc, 0x3c04001f, 0x3c010001, 0x370821,
-0xa03e83c0, 0x2442ffff, 0xaee201cc, 0x9603000a,
-0x3484ffff, 0x8ee201cc, 0x6a1821, 0x2639821,
-0x93202b, 0x10800003, 0x3c02fff5, 0x34421000,
-0x2629821, 0xadab0000, 0x8ee2724c, 0x24420001,
-0x304207ff, 0xaee2724c, 0x8f420240, 0x10400004,
-0x283a023, 0x8ee20e1c, 0x24420001, 0xaee20e1c,
-0xa3a00027, 0x1680fd29, 0x0, 0x12800024,
-0x0, 0x3c010001, 0x370821, 0xac3483c4,
-0x3c010001, 0x370821, 0xac3383c8, 0x3c010001,
-0x370821, 0xac3283cc, 0x93a20037, 0x10400008,
-0x0, 0x3c020001, 0x571021, 0x8c4283cc,
-0x24420004, 0x3c010001, 0x370821, 0xac2283cc,
-0x8ee2724c, 0x8f430280, 0x24420001, 0x304207ff,
-0x14620006, 0x0, 0x8ee201c4, 0x24420001,
-0xaee201c4, 0x80034cc, 0x8ee201c4, 0x8ee201bc,
-0x24420001, 0xaee201bc, 0x80034cc, 0x8ee201bc,
-0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0,
-0x8ee500c4, 0x1021, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0xaee400c0, 0xaee500c4,
-0x8faf002c, 0x24020002, 0x11e2000f, 0x29e20003,
-0x14400017, 0x24020003, 0x15e20015, 0x0,
-0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001,
-0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0,
-0x80034c6, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc,
-0x24630001, 0x2c640001, 0x441021, 0xaee200d8,
-0xaee300dc, 0x8ee200d8, 0x80034c6, 0x8ee300dc,
-0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001,
-0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8,
-0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003,
-0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf0070,
-0x8fbe006c, 0x8fb60068, 0x8fb50064, 0x8fb40060,
-0x8fb3005c, 0x8fb20058, 0x8fb10054, 0x8fb00050,
-0x3e00008, 0x27bd0078, 0x27bdffb0, 0xafb50044,
-0xa821, 0xafb00030, 0x8021, 0xafbf004c,
-0xafb60048, 0xafb40040, 0xafb3003c, 0xafb20038,
-0xafb10034, 0x8ee204d4, 0x24140001, 0x30420001,
-0x1440002a, 0xb021, 0x8f8700e0, 0x8f8800c4,
-0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001,
-0x24841000, 0x420c2, 0x801821, 0x8ee400c8,
-0x8ee500cc, 0x1021, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0xaee400c8, 0xaee500cc,
-0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023,
-0x44102b, 0x10400003, 0x3c02000a, 0x3442f000,
-0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8,
-0xaf8700e4, 0x8003850, 0xaf8700e8, 0x3c020001,
-0x571021, 0x904283c0, 0x1040000b, 0x0,
-0x3c130001, 0x2779821, 0x8e7383c4, 0x3c110001,
-0x2378821, 0x8e3183c8, 0x3c120001, 0x2579021,
-0x80036e8, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4,
-0x10430007, 0x4821, 0x8f8200e4, 0x24090001,
-0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
-0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
-0x8f8200c8, 0x3c040001, 0x24845870, 0xafa20014,
-0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
-0x34a5f000, 0x8003850, 0x0, 0x8fa3001c,
-0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
-0x10400058, 0x2408821, 0x3c020080, 0x621024,
-0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001,
-0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001,
-0xaee201fc, 0x800384a, 0x8ee201fc, 0x3c060004,
-0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008,
-0x8ee20080, 0x3c080020, 0x34078000, 0x24420001,
-0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824,
-0x10660021, 0xc3102b, 0x14400007, 0x0,
-0x106b0011, 0x0, 0x106a0015, 0x0,
-0x8003592, 0x42042, 0x10650023, 0xa3102b,
-0x14400005, 0x0, 0x10690019, 0x0,
-0x8003592, 0x42042, 0x10680021, 0x0,
-0x8003592, 0x42042, 0x8ee20034, 0x24420001,
-0xaee20034, 0x8ee20034, 0x8003592, 0x42042,
-0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec,
-0x8003592, 0x42042, 0x8ee201f0, 0x24420001,
-0xaee201f0, 0x8ee201f0, 0x8003592, 0x42042,
-0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4,
-0x8003592, 0x42042, 0x8ee20030, 0x24420001,
-0xaee20030, 0x8ee20030, 0x8003592, 0x42042,
-0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8,
-0x42042, 0x108702b7, 0x0, 0x8003557,
-0x0, 0x3c020001, 0x571021, 0x904283b2,
-0x14400084, 0x24020001, 0x3c030001, 0x771821,
-0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000,
-0x621024, 0x1040006f, 0x2402ffff, 0x14620005,
-0x24100001, 0x96430004, 0x3402ffff, 0x10620075,
-0x0, 0x92e204d8, 0x14400072, 0x0,
-0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
-0x10400020, 0x3821, 0x3c020001, 0x571021,
-0x8c4283b4, 0x18400016, 0x2821, 0x96260000,
-0x520c0, 0x971021, 0x9442777e, 0x14460009,
-0x971021, 0x94437780, 0x96220002, 0x14620005,
-0x971021, 0x94437782, 0x96220004, 0x50620008,
-0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
-0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
-0x30e200ff, 0x1040027b, 0x0, 0x800361e,
-0x0, 0x2402021, 0xc0022fe, 0x24050006,
-0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
-0x30424000, 0x1440026f, 0xb71021, 0x9443727e,
-0x96220000, 0x1462000b, 0x418c0, 0xb71021,
-0x94437280, 0x96220002, 0x14620006, 0x418c0,
-0xb71021, 0x94437282, 0x96220004, 0x10620035,
-0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
-0x1440025c, 0x2e31021, 0x9448727c, 0x96270000,
-0x828c0, 0xb71021, 0x9442737e, 0x8003600,
-0x3021, 0x420c0, 0x2e41021, 0x9443737c,
-0x2e41021, 0x9448737c, 0x30638000, 0x14600010,
-0x828c0, 0xb71021, 0x9442737e, 0x1447fff5,
-0x1002021, 0xb71021, 0x94437380, 0x96220002,
-0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
-0x96220004, 0x5462ffec, 0x420c0, 0x24060001,
-0x30c200ff, 0x1040023b, 0x0, 0x800361e,
-0x0, 0x97430202, 0x96420000, 0x14620235,
-0x0, 0x97430204, 0x96420002, 0x14620231,
-0x0, 0x97430206, 0x96420004, 0x1462022d,
-0x0, 0x92420000, 0x3a030001, 0x30420001,
-0x431024, 0x10400074, 0x2402ffff, 0x8e230000,
-0x14620004, 0x3402ffff, 0x96230004, 0x1062006f,
-0x24140002, 0x3c020001, 0x571021, 0x904283b2,
-0x1440006a, 0x24140003, 0x92e204d8, 0x14400067,
-0x0, 0x3c020001, 0x571021, 0x8c4283b4,
-0x28420005, 0x10400020, 0x3821, 0x3c020001,
-0x571021, 0x8c4283b4, 0x18400016, 0x2821,
-0x96260000, 0x520c0, 0x971021, 0x9442777e,
-0x14460009, 0x971021, 0x94437780, 0x96220002,
-0x14620005, 0x971021, 0x94437782, 0x96220004,
-0x50620008, 0x24070001, 0x3c020001, 0x571021,
-0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee,
-0x520c0, 0x30e200ff, 0x14400044, 0x24140003,
-0x800384a, 0x0, 0x2402021, 0xc0022fe,
-0x24050006, 0x3044001f, 0x428c0, 0x2e51021,
-0x9442727c, 0x30424000, 0x144001ea, 0xb71021,
-0x9443727e, 0x96220000, 0x1462000b, 0x418c0,
-0xb71021, 0x94437280, 0x96220002, 0x14620006,
-0x418c0, 0xb71021, 0x94437282, 0x96220004,
-0x10620027, 0x418c0, 0x2e31021, 0x9442727c,
-0x30428000, 0x144001d7, 0x2e31021, 0x9448727c,
-0x96270000, 0x828c0, 0xb71021, 0x9442737e,
-0x8003685, 0x3021, 0x420c0, 0x2e41021,
-0x9443737c, 0x2e41021, 0x9448737c, 0x30638000,
-0x14600010, 0x828c0, 0xb71021, 0x9442737e,
-0x1447fff5, 0x1002021, 0xb71021, 0x94437380,
-0x96220002, 0x5462fff1, 0x420c0, 0xb71021,
-0x94437382, 0x96220004, 0x5462ffec, 0x420c0,
-0x24060001, 0x30c200ff, 0x104001b6, 0x0,
-0x8003698, 0x24140003, 0x24140001, 0x8f420260,
-0x53102b, 0x10400049, 0x0, 0x8f8300e4,
-0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
-0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
-0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
-0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
-0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878,
-0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
-0xc002403, 0x34a5f003, 0x8003850, 0x0,
-0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
-0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
-0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
-0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf,
-0x431024, 0x80037f8, 0xaee20000, 0x8ee25240,
-0xafa20010, 0x8ee25244, 0x3c040001, 0x24845884,
-0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006,
-0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
-0xaee201c0, 0x80037f8, 0x8ee201c0, 0x96e20468,
-0x53102b, 0x54400001, 0x3c158000, 0x12600131,
-0x3c0c001f, 0x358cffff, 0x8ee2724c, 0x8f430280,
-0x24420001, 0x304207ff, 0x10620108, 0x0,
-0x12a00014, 0x0, 0x8ee35240, 0x8ee25244,
-0x10620009, 0x26ee5244, 0x8eeb5244, 0x8ee35244,
-0x21140, 0x24425248, 0x2e28021, 0x24630001,
-0x8003712, 0x306800ff, 0x92e27248, 0x1440ffc0,
-0x3c050006, 0x8ee201e0, 0x24420001, 0xaee201e0,
-0x8ee201e0, 0x8ee30e10, 0x8ee20e18, 0x1062ffcb,
-0x26ee0e18, 0x8eeb0e18, 0xa821, 0x8ee30e18,
-0x21140, 0x24420e20, 0x2e28021, 0x24630001,
-0x306801ff, 0x96e2046a, 0x30420010, 0x10400017,
-0x34028100, 0x9643000c, 0x14620014, 0x0,
-0x3c020001, 0x571021, 0x904283c0, 0x1440000f,
-0x0, 0x9642000e, 0xa6020016, 0x8e420008,
-0x8e430004, 0x8e440000, 0x2673fffc, 0xae42000c,
-0xae430008, 0xae440004, 0x9602000e, 0x26310004,
-0x24160001, 0x34420200, 0xa602000e, 0x9603000a,
-0x2605021, 0x73102b, 0x10400002, 0x2606821,
-0x605021, 0x2d42003d, 0x1040002a, 0x3821,
-0x9623000c, 0x24020800, 0x54620027, 0xae110018,
-0x3c020001, 0x571021, 0x904283c0, 0x54400022,
-0xae110018, 0x26220017, 0x182102b, 0x10400013,
-0x0, 0x3c02fff5, 0x511021, 0x90421017,
-0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
-0x621825, 0x10600013, 0x26220010, 0x182102b,
-0x1040000e, 0x0, 0x3c07fff5, 0xf13821,
-0x94e71010, 0x800375e, 0x24e7000e, 0x92220017,
-0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
-0x621825, 0x50600004, 0xae110018, 0x96270010,
-0x24e7000e, 0xae110018, 0x3c020001, 0x571021,
-0x904283c0, 0x2102b, 0x14e00002, 0x24ec0,
-0x1403821, 0x8f830120, 0x27623800, 0x24660020,
-0xc2102b, 0x50400001, 0x27663000, 0x8f820128,
-0x10c20004, 0x0, 0x8f820124, 0x14c20007,
-0x2402000b, 0x8ee201a4, 0x4821, 0x24420001,
-0xaee201a4, 0x80037bf, 0x8ee201a4, 0x8e040000,
-0x8e050004, 0xac620018, 0x1751025, 0x491025,
-0xac710008, 0xa467000e, 0xac62001c, 0xac640000,
-0xac650004, 0x8ee204c0, 0xac620010, 0xaf860120,
-0x92e24e20, 0x14400038, 0x24090001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020007, 0x14620020, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001c, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee34e34, 0x8ee54e30,
-0x24020040, 0x24630001, 0x10620007, 0x0,
-0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
-0x80037a9, 0x0, 0x14a00005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x80037bf, 0x0, 0x8ee24e30, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020007, 0xac820000,
-0x24020001, 0xac820004, 0x15200018, 0x3c050006,
-0x8e020018, 0x3c040001, 0x24845890, 0xafa20010,
-0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021,
-0xc002403, 0xafa30014, 0x32c200ff, 0x1040002b,
-0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c,
-0xa642000c, 0xae430000, 0xae440004, 0xae450008,
-0x96020016, 0x80037f8, 0xa642000e, 0x154d000a,
-0x0, 0x9602000e, 0xa613000a, 0x34420004,
-0xa602000e, 0x3c010001, 0x370821, 0xa02083c0,
-0x80037f6, 0x9821, 0x9604000a, 0x93102b,
-0x10400002, 0x2601821, 0x801821, 0x24020001,
-0xa603000a, 0x3c010001, 0x370821, 0xa02283c0,
-0x9604000a, 0x2248821, 0x191102b, 0x10400003,
-0x3c02fff5, 0x34421000, 0x2228821, 0x2649823,
-0xa821, 0x1660fef4, 0xadc80000, 0x12600021,
-0x32c200ff, 0x3c010001, 0x370821, 0xac3383c4,
-0x3c010001, 0x370821, 0xac3183c8, 0x3c010001,
-0x370821, 0x10400008, 0xac3283cc, 0x3c020001,
-0x571021, 0x8c4283cc, 0x24420004, 0x3c010001,
-0x370821, 0xac2283cc, 0x8ee2724c, 0x8f430280,
-0x24420001, 0x14620006, 0x0, 0x8ee201c4,
-0x24420001, 0xaee201c4, 0x8003850, 0x8ee201c4,
-0x8ee201bc, 0x24420001, 0xaee201bc, 0x8003850,
-0x8ee201bc, 0x97a4001e, 0x2484fffc, 0x801821,
-0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0x24020002,
-0xaee400c0, 0xaee500c4, 0x1282000f, 0x2a820003,
-0x14400017, 0x24020003, 0x16820015, 0x0,
-0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001,
-0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0,
-0x800384a, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc,
-0x24630001, 0x2c640001, 0x441021, 0xaee200d8,
-0xaee300dc, 0x8ee200d8, 0x800384a, 0x8ee300dc,
-0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001,
-0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8,
-0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003,
-0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf004c,
-0x8fb60048, 0x8fb50044, 0x8fb40040, 0x8fb3003c,
-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
-0x27bd0050, 0x27bdff90, 0xafb60060, 0xb021,
-0xafbf0068, 0xafbe0064, 0xafb5005c, 0xafb40058,
-0xafb30054, 0xafb20050, 0xafb1004c, 0xafb00048,
-0x8ee204d4, 0x8821, 0x24150001, 0x30420001,
-0x1440002a, 0xa3a0002f, 0x8f8700e0, 0x8f8800c4,
-0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001,
-0x24841000, 0x420c2, 0x801821, 0x8ee400c8,
-0x8ee500cc, 0x1021, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0xaee400c8, 0xaee500cc,
-0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023,
-0x44102b, 0x10400003, 0x3c02000a, 0x3442f000,
-0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8,
-0xaf8700e4, 0x8003c5b, 0xaf8700e8, 0x3c020001,
-0x571021, 0x904283c0, 0x1040000b, 0x0,
-0x3c130001, 0x2779821, 0x8e7383c4, 0x3c100001,
-0x2178021, 0x8e1083c8, 0x3c120001, 0x2579021,
-0x8003a59, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4,
-0x10430007, 0x3821, 0x8f8200e4, 0x24070001,
-0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
-0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
-0x8f8200c8, 0x3c040001, 0x248458b4, 0xafa20014,
-0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
-0x34a5f200, 0x8003c5b, 0x0, 0x8fa3001c,
-0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
-0x10400058, 0x2408021, 0x3c020080, 0x621024,
-0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001,
-0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001,
-0xaee201fc, 0x8003c55, 0x8ee201fc, 0x3c060004,
-0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008,
-0x8ee20080, 0x3c080020, 0x34078000, 0x24420001,
-0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824,
-0x10660021, 0xc3102b, 0x14400007, 0x0,
-0x106b0011, 0x0, 0x106a0015, 0x0,
-0x8003916, 0x42042, 0x10650023, 0xa3102b,
-0x14400005, 0x0, 0x10690019, 0x0,
-0x8003916, 0x42042, 0x10680021, 0x0,
-0x8003916, 0x42042, 0x8ee20034, 0x24420001,
-0xaee20034, 0x8ee20034, 0x8003916, 0x42042,
-0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec,
-0x8003916, 0x42042, 0x8ee201f0, 0x24420001,
-0xaee201f0, 0x8ee201f0, 0x8003916, 0x42042,
-0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4,
-0x8003916, 0x42042, 0x8ee20030, 0x24420001,
-0xaee20030, 0x8ee20030, 0x8003916, 0x42042,
-0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8,
-0x42042, 0x1087033e, 0x0, 0x80038db,
-0x0, 0x3c020001, 0x571021, 0x904283b2,
-0x14400084, 0x24020001, 0x3c030001, 0x771821,
-0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000,
-0x621024, 0x1040006f, 0x2402ffff, 0x14620005,
-0x24110001, 0x96430004, 0x3402ffff, 0x10620075,
-0x0, 0x92e204d8, 0x14400072, 0x0,
-0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
-0x10400020, 0x3821, 0x3c020001, 0x571021,
-0x8c4283b4, 0x18400016, 0x2821, 0x96060000,
-0x520c0, 0x971021, 0x9442777e, 0x14460009,
-0x971021, 0x94437780, 0x96020002, 0x14620005,
-0x971021, 0x94437782, 0x96020004, 0x50620008,
-0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
-0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
-0x30e200ff, 0x10400302, 0x0, 0x80039a2,
-0x0, 0x2402021, 0xc0022fe, 0x24050006,
-0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
-0x30424000, 0x144002f6, 0xb71021, 0x9443727e,
-0x96020000, 0x1462000b, 0x418c0, 0xb71021,
-0x94437280, 0x96020002, 0x14620006, 0x418c0,
-0xb71021, 0x94437282, 0x96020004, 0x10620035,
-0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
-0x144002e3, 0x2e31021, 0x944d727c, 0x96070000,
-0xd28c0, 0xb71021, 0x9442737e, 0x8003984,
-0x3021, 0x420c0, 0x2e41021, 0x9443737c,
-0x2e41021, 0x944d737c, 0x30638000, 0x14600010,
-0xd28c0, 0xb71021, 0x9442737e, 0x1447fff5,
-0x1a02021, 0xb71021, 0x94437380, 0x96020002,
-0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
-0x96020004, 0x5462ffec, 0x420c0, 0x24060001,
-0x30c200ff, 0x104002c2, 0x0, 0x80039a2,
-0x0, 0x97430202, 0x96420000, 0x146202bc,
-0x0, 0x97430204, 0x96420002, 0x146202b8,
-0x0, 0x97430206, 0x96420004, 0x146202b4,
-0x0, 0x92420000, 0x3a230001, 0x30420001,
-0x431024, 0x10400074, 0x2402ffff, 0x8e030000,
-0x14620004, 0x3402ffff, 0x96030004, 0x1062006f,
-0x24150002, 0x3c020001, 0x571021, 0x904283b2,
-0x1440006a, 0x24150003, 0x92e204d8, 0x14400067,
-0x0, 0x3c020001, 0x571021, 0x8c4283b4,
-0x28420005, 0x10400020, 0x3821, 0x3c020001,
-0x571021, 0x8c4283b4, 0x18400016, 0x2821,
-0x96060000, 0x520c0, 0x971021, 0x9442777e,
-0x14460009, 0x971021, 0x94437780, 0x96020002,
-0x14620005, 0x971021, 0x94437782, 0x96020004,
-0x50620008, 0x24070001, 0x3c020001, 0x571021,
-0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee,
-0x520c0, 0x30e200ff, 0x14400044, 0x24150003,
-0x8003c55, 0x0, 0x2402021, 0xc0022fe,
-0x24050006, 0x3044001f, 0x428c0, 0x2e51021,
-0x9442727c, 0x30424000, 0x14400271, 0xb71021,
-0x9443727e, 0x96020000, 0x1462000b, 0x418c0,
-0xb71021, 0x94437280, 0x96020002, 0x14620006,
-0x418c0, 0xb71021, 0x94437282, 0x96020004,
-0x10620027, 0x418c0, 0x2e31021, 0x9442727c,
-0x30428000, 0x1440025e, 0x2e31021, 0x944d727c,
-0x96070000, 0xd28c0, 0xb71021, 0x9442737e,
-0x8003a09, 0x3021, 0x420c0, 0x2e41021,
-0x9443737c, 0x2e41021, 0x944d737c, 0x30638000,
-0x14600010, 0xd28c0, 0xb71021, 0x9442737e,
-0x1447fff5, 0x1a02021, 0xb71021, 0x94437380,
-0x96020002, 0x5462fff1, 0x420c0, 0xb71021,
-0x94437382, 0x96020004, 0x5462ffec, 0x420c0,
-0x24060001, 0x30c200ff, 0x1040023d, 0x0,
-0x8003a1c, 0x24150003, 0x24150001, 0x8f420260,
-0x53102b, 0x10400036, 0x0, 0x8f8300e4,
-0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
-0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
-0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
-0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
-0xafa20010, 0x8f8200e4, 0x3c040001, 0x248458c0,
-0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
-0xc002403, 0x34a5f203, 0x8003c5b, 0x0,
-0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
-0x248458cc, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
-0x3c050006, 0xc002403, 0x34a5f202, 0x8ee201c0,
-0x24420001, 0xaee201c0, 0x8003c02, 0x8ee201c0,
-0x96e20468, 0x53102b, 0x54400001, 0x3c168000,
-0x126001cb, 0x3c0e001f, 0x35ceffff, 0x3c0ffff5,
-0x35ef1000, 0x241e0040, 0x8ee2724c, 0x8f430280,
-0x24420001, 0x304207ff, 0x1062019e, 0x0,
-0x12c00012, 0x0, 0x8ee35240, 0x8ee25244,
-0x1062000a, 0x26f85244, 0x8ef45244, 0xafb80024,
-0x8ee35244, 0x21140, 0x24425248, 0x2e28821,
-0x24630001, 0x8003a85, 0x306d00ff, 0x8ee201e0,
-0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10,
-0x8ee20e18, 0x1062ffca, 0x26f80e18, 0x8ef40e18,
-0xb021, 0xafb80024, 0x8ee30e18, 0x21140,
-0x24420e20, 0x2e28821, 0x24630001, 0x306d01ff,
-0x96e2046a, 0x30420010, 0x10400018, 0x34028100,
-0x9643000c, 0x14620015, 0x0, 0x3c020001,
-0x571021, 0x904283c0, 0x14400010, 0x0,
-0x9642000e, 0xa6220016, 0x8e420008, 0x8e430004,
-0x8e440000, 0x2673fffc, 0xae42000c, 0xae430008,
-0xae440004, 0x9622000e, 0x26100004, 0x24180001,
-0xa3b8002f, 0x34420200, 0xa622000e, 0x8e220000,
-0x8e230004, 0x3c040001, 0x34843800, 0x2003021,
-0x306a0007, 0x20a8023, 0x3641021, 0x202102b,
-0x10400005, 0x26a9821, 0x2041023, 0x3621823,
-0x3c020020, 0x438023, 0x26620007, 0x9623000a,
-0x2418fff8, 0x58c824, 0x6a1821, 0x79102b,
-0x10400002, 0x3206021, 0x606021, 0x1801821,
-0x24620007, 0x2418fff8, 0x586024, 0x26c102b,
-0x14400004, 0x1932823, 0x1832823, 0x8003ac3,
-0xc31021, 0xd31021, 0x4a2023, 0x1c4102b,
-0x54400001, 0x8f2021, 0x25420040, 0x4c102b,
-0x14400035, 0x5821, 0x94c3000c, 0x24020800,
-0x54620032, 0xae260018, 0x3c020001, 0x571021,
-0x904283c0, 0x5440002d, 0xae260018, 0x24c20017,
-0x1c2102b, 0x10400013, 0x0, 0x3c02fff5,
-0x461021, 0x90421017, 0x38430006, 0x2c630001,
-0x38420011, 0x2c420001, 0x621825, 0x10600014,
-0x24c20010, 0x1c2102b, 0x1040000e, 0x0,
-0x3c0bfff5, 0x1665821, 0x956b1010, 0x8003af4,
-0x2562000e, 0x90c20017, 0x38430006, 0x2c630001,
-0x38420011, 0x2c420001, 0x621825, 0x10600005,
-0x1601821, 0x94cb0010, 0x2562000e, 0x4a5821,
-0x1601821, 0x24620007, 0x2418fff8, 0x585824,
-0xc31021, 0x4a2023, 0x1c4102b, 0x10400002,
-0x1632823, 0x8f2021, 0xae260018, 0x3c020001,
-0x571021, 0x904283c0, 0x2102b, 0x216c0,
-0x15600002, 0xafa20044, 0x1805821, 0x30820001,
-0x10400007, 0x4021, 0x90880000, 0x24840001,
-0x1c4102b, 0x10400002, 0x24a5ffff, 0x8f2021,
-0x50a00012, 0x81c02, 0x2ca20002, 0x54400009,
-0x24a5ffff, 0x94820000, 0x24840002, 0x1024021,
-0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b21,
-0x8f2021, 0x90820000, 0x21200, 0x1024021,
-0x14a0fff2, 0x2ca20002, 0x81c02, 0x3102ffff,
-0x624021, 0x3108ffff, 0x1402821, 0x11400011,
-0x2002021, 0x2ca20002, 0x54400009, 0x24a5ffff,
-0x94820000, 0x24840002, 0x1024021, 0x1c4102b,
-0x10400006, 0x24a5fffe, 0x8003b38, 0x8f2021,
-0x90820000, 0x21200, 0x1024021, 0x14a0fff2,
-0x2ca20002, 0x81c02, 0x3102ffff, 0x624021,
-0x81c02, 0x3102ffff, 0x8f890120, 0x624021,
-0x27623800, 0x25230020, 0x62102b, 0x14400002,
-0x3108ffff, 0x27633000, 0x8f820128, 0x10620004,
-0x0, 0x8f820124, 0x14620007, 0x1402821,
-0x8ee201a4, 0x3821, 0x24420001, 0xaee201a4,
-0x8003bc9, 0x8ee201a4, 0x8e260000, 0x8e270004,
-0x81400, 0x3448000b, 0xad300008, 0xa52b000e,
-0xad280018, 0x8fb80044, 0x2021, 0x2961025,
-0x581025, 0xad22001c, 0xe5102b, 0xe53823,
-0xc43023, 0xc23023, 0xad260000, 0xad270004,
-0x8ee204c0, 0xad220010, 0xaf830120, 0x92e24e20,
-0x1440005f, 0x24070001, 0x2502ffee, 0x2c420002,
-0x14400003, 0x24020011, 0x15020024, 0x0,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c830000, 0x24020012, 0x1462000f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062000b, 0x0,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x105e002a, 0x0,
-0x8003ba8, 0x0, 0x8ee24e30, 0x24420001,
-0x505e0003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8003bc6, 0x24020012, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x105e0007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x8003bb4,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400012, 0xac800000, 0x8003bc9,
-0x0, 0x8ee24e30, 0x24420001, 0x505e0003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020007, 0xac820000, 0x24020001, 0xac820004,
-0x14e00019, 0x3c050006, 0x3c040001, 0x24845890,
-0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000,
-0x8e230004, 0x2203021, 0x1603821, 0xc002403,
-0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100,
-0x8e430004, 0x8e440008, 0x8e45000c, 0xa642000c,
-0xae430000, 0xae440004, 0xae450008, 0x96220016,
-0x8003c02, 0xa642000e, 0x1599000a, 0x26a1823,
-0x9622000e, 0xa623000a, 0x34420004, 0xa622000e,
-0x3c010001, 0x370821, 0xa02083c0, 0x8003bff,
-0x9821, 0x9624000a, 0x83102b, 0x54400001,
-0x801821, 0x24020001, 0xa623000a, 0x3c010001,
-0x370821, 0xa02283c0, 0x9622000a, 0x4a1821,
-0x2038021, 0x1d0102b, 0x54400001, 0x20f8021,
-0x2639823, 0xb021, 0x8fb80024, 0x1660fe5e,
-0xaf0d0000, 0x12600022, 0x0, 0x3c010001,
-0x370821, 0xac3383c4, 0x3c010001, 0x370821,
-0xac3083c8, 0x3c010001, 0x370821, 0xac3283cc,
-0x93a2002f, 0x10400008, 0x0, 0x3c020001,
-0x571021, 0x8c4283cc, 0x24420004, 0x3c010001,
-0x370821, 0xac2283cc, 0x8f430280, 0x8ee2724c,
-0x14620006, 0x0, 0x8ee201c4, 0x24420001,
-0xaee201c4, 0x8003c5b, 0x8ee201c4, 0x8ee201bc,
-0x24420001, 0xaee201bc, 0x8003c5b, 0x8ee201bc,
-0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0,
-0x8ee500c4, 0x1021, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0x24020002, 0xaee400c0,
-0xaee500c4, 0x12a2000f, 0x2aa20003, 0x14400017,
-0x24020003, 0x16a20015, 0x0, 0x8ee200d0,
-0x8ee300d4, 0x24630001, 0x2c640001, 0x441021,
-0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x8003c55,
-0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001,
-0x2c640001, 0x441021, 0xaee200d8, 0xaee300dc,
-0x8ee200d8, 0x8003c55, 0x8ee300dc, 0x8ee200c8,
-0x8ee300cc, 0x24630001, 0x2c640001, 0x441021,
-0xaee200c8, 0xaee300cc, 0x8ee200c8, 0x8ee300cc,
-0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008,
-0xaf8300e4, 0xaf8300e8, 0x8fbf0068, 0x8fbe0064,
-0x8fb60060, 0x8fb5005c, 0x8fb40058, 0x8fb30054,
-0x8fb20050, 0x8fb1004c, 0x8fb00048, 0x3e00008,
-0x27bd0070, 0x27bdffe0, 0xafbf0018, 0x8ee30e14,
-0x8ee20e0c, 0x10620074, 0x0, 0x8ee30e0c,
-0x8ee20e14, 0x622023, 0x4820001, 0x24840200,
-0x8ee30e18, 0x8ee20e14, 0x43102b, 0x14400004,
-0x24020200, 0x8ee30e14, 0x8003c7d, 0x431823,
-0x8ee20e18, 0x8ee30e14, 0x431023, 0x2443ffff,
-0x804821, 0x69102a, 0x54400001, 0x604821,
-0x8f870100, 0x27623000, 0x24e80020, 0x102102b,
-0x50400001, 0x27682800, 0x8f820108, 0x11020004,
-0x0, 0x8f820104, 0x15020007, 0x1021,
-0x8ee201a8, 0x2021, 0x24420001, 0xaee201a8,
-0x8003cbf, 0x8ee201a8, 0x8ee40e14, 0x42140,
-0x801821, 0x8ee40460, 0x8ee50464, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0xace40000,
-0xace50004, 0x8ee30e14, 0x91140, 0xa4e2000e,
-0x24020002, 0xace20018, 0x31940, 0x24630e20,
-0x2e31021, 0xace20008, 0x8ee20e14, 0xace2001c,
-0x8ee204cc, 0xace20010, 0xaf880100, 0x92e204ec,
-0x14400011, 0x24040001, 0x8ee24e28, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
-0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
-0x24424e38, 0x2e21821, 0x24020002, 0xac620000,
-0x24020001, 0xac620004, 0x1480000e, 0x24030040,
-0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007,
-0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001,
-0x248458d4, 0xc002403, 0x34a5f001, 0x8003cdd,
-0x0, 0x8ee20500, 0x24420001, 0x50430003,
-0x1021, 0x8ee20500, 0x24420001, 0xaee20500,
-0x8ee20500, 0x21080, 0x571021, 0xac490508,
-0x8ee20e14, 0x491021, 0x304201ff, 0xaee20e14,
-0x8ee30e14, 0x8ee20e0c, 0x14620005, 0x0,
-0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0,
-0xafbf0018, 0x8ee3523c, 0x8ee25238, 0x10620074,
-0x0, 0x8ee35238, 0x8ee2523c, 0x622023,
-0x4820001, 0x24840100, 0x8ee35244, 0x8ee2523c,
-0x43102b, 0x14400004, 0x24020100, 0x8ee3523c,
-0x8003cff, 0x431823, 0x8ee25244, 0x8ee3523c,
-0x431023, 0x2443ffff, 0x804821, 0x69102a,
-0x54400001, 0x604821, 0x8f870100, 0x27623000,
-0x24e80020, 0x102102b, 0x50400001, 0x27682800,
-0x8f820108, 0x11020004, 0x0, 0x8f820104,
-0x15020007, 0x1021, 0x8ee201a8, 0x2021,
-0x24420001, 0xaee201a8, 0x8003d41, 0x8ee201a8,
-0x8ee4523c, 0x42140, 0x801821, 0x8ee40470,
-0x8ee50474, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xace40000, 0xace50004, 0x8ee3523c,
-0x91140, 0xa4e2000e, 0x24020003, 0xace20018,
-0x31940, 0x24635248, 0x2e31021, 0xace20008,
-0x8ee2523c, 0xace2001c, 0x8ee204cc, 0xace20010,
-0xaf880100, 0x92e204ec, 0x14400011, 0x24040001,
-0x8ee24e28, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e21821,
-0x24020003, 0xac620000, 0x24020001, 0xac620004,
-0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010,
-0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238,
-0x8ee75240, 0x3c040001, 0x248458e0, 0xc002403,
-0x34a5f010, 0x8003d5f, 0x0, 0x8ee20500,
-0x24420001, 0x50430003, 0x1021, 0x8ee20500,
-0x24420001, 0xaee20500, 0x8ee20500, 0x21080,
-0x571021, 0xac490508, 0x8ee2523c, 0x491021,
-0x304200ff, 0xaee2523c, 0x8ee3523c, 0x8ee25238,
-0x14620005, 0x0, 0x8f820060, 0x2403feff,
-0x431024, 0xaf820060, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x8f820120, 0x8ee34e34, 0x8f820124,
-0x8f860128, 0x24020040, 0x24630001, 0x50620003,
-0x1021, 0x8ee24e34, 0x24420001, 0xaee24e34,
-0x8ee24e34, 0x8ee44e34, 0x8ee34e30, 0x210c0,
-0x24425038, 0x14830007, 0x2e22821, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8003d92,
-0xaca00000, 0x8ee24e34, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e34, 0x24420001,
-0x210c0, 0x24425038, 0x2e22821, 0x8ca20004,
-0x8f830128, 0x21140, 0x621821, 0xaf830128,
-0xaca00000, 0x8cc20018, 0x2443fffe, 0x2c620012,
-0x10400008, 0x31080, 0x3c010001, 0x220821,
-0x8c2258f0, 0x400008, 0x0, 0x24020001,
-0xaee24e24, 0x3e00008, 0x0, 0x27bdffc8,
-0xafbf0030, 0xafb5002c, 0xafb40028, 0xafb30024,
-0xafb20020, 0xafb1001c, 0xafb00018, 0x8f830128,
-0x8f820124, 0x106202b0, 0x9821, 0x3c11001f,
-0x3631ffff, 0x3c12fff5, 0x36521000, 0x24150012,
-0x24140040, 0x8f8c0128, 0x8f820128, 0x24420020,
-0xaf820128, 0x9182001b, 0x8f830128, 0x2443fffe,
-0x2c620012, 0x1040029c, 0x31080, 0x3c010001,
-0x220821, 0x8c225948, 0x400008, 0x0,
-0x8f420218, 0x30420100, 0x10400007, 0x0,
-0x95830016, 0x95820018, 0x621823, 0x31402,
-0x431021, 0xa5820016, 0x8d82001c, 0x3c038000,
-0x3044ffff, 0x436824, 0x3c030800, 0x431824,
-0x11a00004, 0xad84001c, 0x41140, 0x8003dd8,
-0x24425248, 0x41140, 0x24420e20, 0x2e25821,
-0x9562000e, 0x3042fffc, 0x10600004, 0xa562000e,
-0x95840016, 0x8003ec0, 0x0, 0x8d690018,
-0x4021, 0x952a0000, 0x25290002, 0x95270000,
-0x25290002, 0x95260000, 0x25290002, 0x95250000,
-0x25290002, 0x95240000, 0x25290002, 0x95230000,
-0x25290002, 0x95220000, 0x25290002, 0x1475021,
-0x1465021, 0x1455021, 0x1445021, 0x1435021,
-0x1425021, 0xa1c02, 0x3142ffff, 0x625021,
-0xa1c02, 0x3142ffff, 0x625021, 0x96e2046a,
-0x314effff, 0x30420002, 0x10400044, 0x5021,
-0x25220014, 0x222102b, 0x10400014, 0x1201821,
-0x2405000a, 0x2021, 0x223102b, 0x54400001,
-0x721821, 0x94620000, 0x24630002, 0x24a5ffff,
-0x14a0fff9, 0x822021, 0x41c02, 0x3082ffff,
-0x622021, 0x41402, 0x3083ffff, 0x431021,
-0x3042ffff, 0x8003e33, 0x1425021, 0x952a0000,
-0x25290002, 0x95280000, 0x25290002, 0x95270000,
-0x25290002, 0x95260000, 0x25290002, 0x95250000,
-0x25290002, 0x95230000, 0x25290002, 0x95220000,
-0x25290002, 0x95240000, 0x25290002, 0x1485021,
-0x1475021, 0x1465021, 0x1455021, 0x1435021,
-0x1425021, 0x95220000, 0x95230002, 0x1445021,
-0x1425021, 0x1435021, 0xa1c02, 0x3142ffff,
-0x625021, 0xa1c02, 0x3142ffff, 0x625021,
-0x3148ffff, 0x51000001, 0x3408ffff, 0x8d620018,
-0x9443000c, 0x24020800, 0x54620005, 0xa5680010,
-0x9562000e, 0x34420002, 0xa562000e, 0xa5680010,
-0x96e2046a, 0x2821, 0x30420008, 0x14400056,
-0x3021, 0x8d630018, 0x24620024, 0x222102b,
-0x10400034, 0x24690010, 0x229102b, 0x54400001,
-0x1324821, 0x95250000, 0x24690014, 0x229102b,
-0x10400002, 0x24a5ffec, 0x1324821, 0x95220000,
-0x30420fff, 0x14400003, 0x25290002, 0x8003e60,
-0x24130001, 0x9821, 0xa03021, 0x229102b,
-0x54400001, 0x1324821, 0x91220001, 0x25290002,
-0xa22821, 0x229102b, 0x54400001, 0x1324821,
-0x25290002, 0x229102b, 0x54400001, 0x1324821,
-0x95220000, 0x25290002, 0xa22821, 0x229102b,
-0x54400001, 0x1324821, 0x95220000, 0x25290002,
-0xa22821, 0x229102b, 0x54400001, 0x1324821,
-0x95220000, 0x25290002, 0xa22821, 0x229102b,
-0x54400001, 0x1324821, 0x95220000, 0x8003e99,
-0xa22821, 0x94650010, 0x94620014, 0x24690016,
-0x30420fff, 0x14400003, 0x24a5ffec, 0x8003e8c,
-0x24130001, 0x9821, 0xa03021, 0x91230001,
-0x25290004, 0x95220000, 0x25290002, 0x95240000,
-0x25290002, 0xa32821, 0xa22821, 0x95220000,
-0x95230002, 0xa42821, 0xa22821, 0xa32821,
-0x51c02, 0x30a2ffff, 0x622821, 0x51c02,
-0x30a2ffff, 0x622821, 0x96e2046a, 0x30420001,
-0x1040001e, 0x2021, 0x95820016, 0x4e2023,
-0x41402, 0x822021, 0x326200ff, 0x50400002,
-0x862021, 0x852021, 0x41402, 0x822021,
-0x3084ffff, 0x50800001, 0x3404ffff, 0x8d620018,
-0x24430017, 0x223102b, 0x54400001, 0x721821,
-0x90620000, 0x38430011, 0x2c630001, 0x38420006,
-0x2c420001, 0x621825, 0x10600004, 0x0,
-0x9562000e, 0x34420001, 0xa562000e, 0x9562000e,
-0x240a0002, 0x30420004, 0x10400002, 0xa5640012,
-0x240a0004, 0x8f880120, 0x27623800, 0x25090020,
-0x122102b, 0x50400001, 0x27693000, 0x8f820128,
-0x11220004, 0x0, 0x8f820124, 0x15220007,
-0x24040020, 0x8ee201a4, 0x8021, 0x24420001,
-0xaee201a4, 0x8003f4f, 0x8ee201a4, 0x8ee5724c,
-0x8ee60490, 0x8ee70494, 0xad0b0008, 0xa504000e,
-0xad0a0018, 0x52940, 0xa01821, 0x1021,
-0xe33821, 0xe3202b, 0xc23021, 0xc43021,
-0xad060000, 0xad070004, 0x8ee2724c, 0x4d1025,
-0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120,
-0x92e24e20, 0x14400060, 0x24100001, 0x2543ffee,
-0x2c630002, 0x39420011, 0x2c420001, 0x621825,
-0x10600024, 0x0, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c820000, 0x1455000f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062000b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x1054002b,
-0x0, 0x8003f2e, 0x0, 0x8ee24e30,
-0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020001, 0x8003f4e,
-0xac950000, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007,
-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
-0x0, 0x8003f3a, 0x0, 0x14600005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400012,
-0xac800000, 0x8003f4f, 0x0, 0x8ee24e30,
-0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020007, 0xac820000,
-0x24020001, 0xac820004, 0x1600000d, 0x0,
-0x8f820120, 0x3c040001, 0x24845938, 0xafa00014,
-0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008,
-0xc002403, 0x34a50001, 0x8004057, 0x0,
-0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006,
-0xaee2724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0,
-0x8003f6b, 0x8ee201d0, 0x8ee201cc, 0x2442ffff,
-0xaee201cc, 0x8ee201cc, 0x8ee201d8, 0x2442ffff,
-0xaee201d8, 0x8004057, 0x8ee201d8, 0x8f420240,
-0x104000e5, 0x0, 0x8ee20e1c, 0x24420001,
-0x8004057, 0xaee20e1c, 0x9582001e, 0xad82001c,
-0x8f420240, 0x10400072, 0x0, 0x8ee20e1c,
-0x24420001, 0xaee20e1c, 0x8f430240, 0x43102b,
-0x144000d5, 0x0, 0x8f830120, 0x27623800,
-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
-0x14c20007, 0x0, 0x8ee201a4, 0x8021,
-0x24420001, 0xaee201a4, 0x8003fda, 0x8ee201a4,
-0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac,
-0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
-0x24020011, 0xac620018, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400034, 0x24100001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c820000, 0x1455001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007,
-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
-0x0, 0x8003fc6, 0x0, 0x14600005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400011,
-0xac800000, 0x8003fda, 0x0, 0x8ee24e30,
-0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020001, 0xac950000,
-0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c,
-0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010,
-0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002403,
-0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188,
-0x24420001, 0xaee20188, 0x8004050, 0x8ee20188,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
-0x8004044, 0x8ee201a4, 0x8ee2724c, 0xac62001c,
-0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008,
-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400034, 0x24100001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x1455001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x10540007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x8004030,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400011, 0xac800000, 0x8004044,
-0x0, 0x8ee24e30, 0x24420001, 0x50540003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020001, 0xac950000, 0xac820004, 0x1600000b,
-0x0, 0x8ee2724c, 0x3c040001, 0x248458a8,
-0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280,
-0x3c050009, 0xc002403, 0x34a5f008, 0x8ee20174,
-0x24420001, 0xaee20174, 0x8004057, 0x8ee20174,
-0x24020001, 0xaee24e24, 0x8f830128, 0x8f820124,
-0x1462fd58, 0x0, 0x8fbf0030, 0x8fb5002c,
-0x8fb40028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
-0x8fb00018, 0x3e00008, 0x27bd0038, 0x27bdffe8,
-0x27840208, 0x27450200, 0x24060008, 0xafbf0014,
-0xc00249a, 0xafb00010, 0x2021, 0x24100001,
-0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204,
-0xaf820214, 0x8f460248, 0x24030004, 0x3c020040,
-0x3c010001, 0xac235cc4, 0x3c010001, 0xac235cc8,
-0x3c010001, 0xac205d9c, 0x3c010001, 0xac225cc0,
-0x3c010001, 0xac235cc8, 0xc005108, 0x24050004,
-0xc004822, 0x0, 0x8ee20000, 0x3c03feff,
-0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00,
-0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac,
-0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018,
-0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018,
-0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001,
-0x248459f0, 0xc002403, 0x3821, 0x8ee20280,
-0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200,
-0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400,
-0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020,
-0xafb1001c, 0xafb00018, 0x8f900220, 0x8ee20214,
-0x3821, 0x24420001, 0xaee20214, 0x8ee20214,
-0x3c020300, 0x2021024, 0x10400027, 0x3c110400,
-0xc00429b, 0x0, 0x3c020100, 0x2021024,
-0x10400007, 0x0, 0x8ee20218, 0x24420001,
-0xaee20218, 0x8ee20218, 0x80040c6, 0x3c03fdff,
-0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c,
-0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff,
-0x8ee20000, 0x3c040001, 0x248459fc, 0x3c050008,
-0x2003021, 0x431024, 0xaee20000, 0x8f820220,
-0x3821, 0x3c030300, 0x481024, 0x431025,
-0xaf820220, 0xafa00010, 0xc002403, 0xafa00014,
-0x8004296, 0x0, 0x2111024, 0x1040001f,
-0x3c024000, 0x8f830224, 0x24021402, 0x1462000b,
-0x3c03fdff, 0x3c040001, 0x24845a08, 0x3c050008,
-0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff,
-0xc002403, 0x3821, 0x3c03fdff, 0x8ee20000,
-0x3463ffff, 0x2002021, 0x431024, 0xc004e54,
-0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220,
-0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff,
-0x431024, 0x8004295, 0x511025, 0x2021024,
-0x10400142, 0x0, 0x8ee2022c, 0x24420001,
-0xaee2022c, 0x8ee2022c, 0x8f820220, 0x3c0308ff,
-0x3463ffff, 0x431024, 0x34420004, 0xaf820220,
-0x8f830054, 0x8f820054, 0x800410e, 0x24630002,
-0x8f820054, 0x621023, 0x2c420003, 0x1440fffc,
-0x0, 0x8f8600e0, 0x8f8400e4, 0x30c20007,
-0x10400012, 0x0, 0x8f8300e4, 0x2402fff8,
-0xc21024, 0x1043000d, 0x0, 0x8f820054,
-0x8f8300e0, 0x14c30009, 0x24440050, 0x8f820054,
-0x821023, 0x2c420051, 0x10400004, 0x0,
-0x8f8200e0, 0x10c2fff9, 0x0, 0x8f820220,
-0x3c0308ff, 0x3463fffd, 0x431024, 0xaf820220,
-0x8f8600e0, 0x30c20007, 0x10400003, 0x2402fff8,
-0xc23024, 0xaf8600e0, 0x8f8300c4, 0x3c02001f,
-0x3442ffff, 0x24680008, 0x48102b, 0x10400003,
-0x3c02fff5, 0x34421000, 0x1024021, 0x8f8b00c8,
-0x8f850120, 0x8f840124, 0x8004145, 0x6021,
-0x27623800, 0x82102b, 0x50400001, 0x27643000,
-0x10a40010, 0x318200ff, 0x8c820018, 0x38430007,
-0x2c630001, 0x3842000b, 0x2c420001, 0x621825,
-0x5060fff3, 0x24840020, 0x8ee20240, 0x240c0001,
-0x24420001, 0xaee20240, 0x8ee20240, 0x8c8b0008,
-0x318200ff, 0x14400065, 0x0, 0x3c020001,
-0x571021, 0x904283c0, 0x14400060, 0x0,
-0x8f8400e4, 0xc41023, 0x218c3, 0x4620001,
-0x24630200, 0x8f8900c4, 0x10600005, 0x24020001,
-0x10620009, 0x0, 0x8004187, 0x0,
-0x8ee20230, 0x1205821, 0x24420001, 0xaee20230,
-0x80041bc, 0x8ee20230, 0x8ee20234, 0x3c05000a,
-0x24420001, 0xaee20234, 0x8c8b0000, 0x34a5f000,
-0x8ee20234, 0x12b1823, 0xa3102b, 0x54400001,
-0x651821, 0x2c62233f, 0x14400040, 0x0,
-0x8f8200e8, 0x24420008, 0xaf8200e8, 0x8f8200e8,
-0x8f8200e4, 0x1205821, 0x24420008, 0xaf8200e4,
-0x80041bc, 0x8f8200e4, 0x8ee20238, 0x3c03000a,
-0x24420001, 0xaee20238, 0x8c840000, 0x3463f000,
-0x8ee20238, 0x883823, 0x67102b, 0x54400001,
-0xe33821, 0x3c020003, 0x34420d40, 0x47102b,
-0x10400003, 0x0, 0x80041bc, 0x805821,
-0x8f8200e4, 0x24440008, 0xaf8400e4, 0x8f8400e4,
-0x10860018, 0x3c05000a, 0x34a5f000, 0x3c0a0003,
-0x354a0d40, 0x8ee2007c, 0x24420001, 0xaee2007c,
-0x8c830000, 0x8ee2007c, 0x683823, 0xa7102b,
-0x54400001, 0xe53821, 0x147102b, 0x54400007,
-0x605821, 0x8f8200e4, 0x24440008, 0xaf8400e4,
-0x8f8400e4, 0x1486ffef, 0x0, 0x14860005,
-0x0, 0x1205821, 0xaf8600e4, 0x80041bc,
-0xaf8600e8, 0xaf8400e4, 0xaf8400e8, 0x8f8200c8,
-0x3c03000a, 0x3463f000, 0x483823, 0x67102b,
-0x54400001, 0xe33821, 0x3c020003, 0x34420d3f,
-0x47102b, 0x54400007, 0x6021, 0x1683823,
-0x67102b, 0x54400003, 0xe33821, 0x80041cf,
-0x3c020003, 0x3c020003, 0x34420d3f, 0x47102b,
-0x14400016, 0x318200ff, 0x14400006, 0x0,
-0x3c020001, 0x571021, 0x904283c0, 0x1040000f,
-0x0, 0x8ee2023c, 0x3c04fdff, 0x8ee30000,
-0x3484ffff, 0x24420001, 0xaee2023c, 0x8ee2023c,
-0x24020001, 0x641824, 0x3c010001, 0x370821,
-0xa02283b8, 0x800422c, 0xaee30000, 0xaf8b00c8,
-0x8f8300c8, 0x8f8200c4, 0x3c04000a, 0x3484f000,
-0x623823, 0x87102b, 0x54400001, 0xe43821,
-0x3c020003, 0x34420d40, 0x47102b, 0x2ce30001,
-0x431025, 0x10400008, 0x0, 0x8f820220,
-0x3c0308ff, 0x3463ffff, 0x431024, 0x3c034000,
-0x431025, 0xaf820220, 0x8f8600e0, 0x8f8400e4,
-0x10c4002a, 0x0, 0x8ee2007c, 0x24420001,
-0xaee2007c, 0x8ee2007c, 0x24c2fff8, 0xaf8200e0,
-0x3c020001, 0x8c427e30, 0x3c030008, 0x8f8600e0,
-0x431024, 0x1040001d, 0x0, 0x10c4001b,
-0x240dfff8, 0x3c0a000a, 0x354af000, 0x3c0c0080,
-0x24850008, 0x27622800, 0x50a20001, 0x27651800,
-0x8c880004, 0x8c820000, 0x8ca90000, 0x3103ffff,
-0x431021, 0x4d1024, 0x24430010, 0x6b102b,
-0x54400001, 0x6a1821, 0x12b102b, 0x54400001,
-0x12a4821, 0x10690002, 0x10c1025, 0xac820004,
-0xa02021, 0x14c4ffeb, 0x24850008, 0x8f820220,
-0x3c0308ff, 0x3463ffff, 0x431024, 0x34420002,
-0xaf820220, 0x8f830054, 0x8f820054, 0x8004237,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff,
-0x3463fffb, 0x431024, 0xaf820220, 0x6010055,
-0x0, 0x8ee20228, 0x24420001, 0xaee20228,
-0x8ee20228, 0x8f820220, 0x3c0308ff, 0x3463ffff,
-0x431024, 0x34420004, 0xaf820220, 0x8f830054,
-0x8f820054, 0x8004251, 0x24630002, 0x8f820054,
-0x621023, 0x2c420003, 0x1440fffc, 0x0,
-0x8f8600e0, 0x30c20007, 0x10400012, 0x0,
-0x8f8300e4, 0x2402fff8, 0xc21024, 0x1043000d,
-0x0, 0x8f820054, 0x8f8300e0, 0x14c30009,
-0x24440032, 0x8f820054, 0x821023, 0x2c420033,
-0x10400004, 0x0, 0x8f8200e0, 0x10c2fff9,
-0x0, 0x8f820220, 0x3c0308ff, 0x3463fffd,
-0x431024, 0xaf820220, 0x8f8600e0, 0x30c20007,
-0x10400003, 0x2402fff8, 0xc23024, 0xaf8600e0,
-0x240301f5, 0x8f8200e8, 0x673823, 0x718c0,
-0x431021, 0xaf8200e8, 0x8f8200e8, 0xaf8200e4,
-0x8ee2007c, 0x3c0408ff, 0x3484ffff, 0x471021,
-0xaee2007c, 0x8f820220, 0x3c038000, 0x34630002,
-0x441024, 0x431025, 0xaf820220, 0x8f830054,
-0x8f820054, 0x800428d, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024,
-0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
-0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425cd8,
-0x27bdffd8, 0x10400012, 0xafbf0020, 0x3c040001,
-0x24845a14, 0x3c050008, 0x24020001, 0x3c010001,
-0x370821, 0xac2283ac, 0xafa00010, 0xafa00014,
-0x8f860220, 0x34a50498, 0x3c010001, 0xac205cd8,
-0x3c010001, 0xac225ccc, 0xc002403, 0x3821,
-0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024,
-0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe,
-0x431024, 0x30840002, 0x1080011e, 0xaee204d0,
-0x8ee204d4, 0x2403fffd, 0x431024, 0xaee204d4,
-0x8f820044, 0x3c030600, 0x34632000, 0x34420020,
-0xaf820044, 0xafa30018, 0x8ee20608, 0x8f430228,
-0x24420001, 0x304a00ff, 0x514300fe, 0xafa00010,
-0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
-0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054,
-0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
-0x1040006a, 0x5821, 0x24180008, 0x240f000d,
-0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120,
-0x27623800, 0x24e80020, 0x102102b, 0x50400001,
-0x27683000, 0x8f820128, 0x11020004, 0x0,
-0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
-0x2821, 0x24420001, 0xaee201a4, 0x800433d,
-0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
-0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0xace40000, 0xace50004,
-0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c,
-0x210c0, 0x2442060c, 0x2e21021, 0xace20008,
-0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
-0x14400033, 0x24050001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c820000, 0x144d001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007,
-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
-0x0, 0x800432a, 0x0, 0x14600005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
-0xac800000, 0x800433d, 0x0, 0x8ee24e30,
-0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004,
-0x54a00006, 0x240b0001, 0x8f820054, 0x1221023,
-0x2c420033, 0x1440ff9d, 0x0, 0x316300ff,
-0x24020001, 0x54620079, 0xafa00010, 0xaeea0608,
-0x8f830054, 0x8f820054, 0x24690032, 0x1221023,
-0x2c420033, 0x10400061, 0x5821, 0x240d0008,
-0x240c0011, 0x24080012, 0x24070040, 0x240a0001,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x2821, 0x24420001, 0xaee201a4,
-0x80043a9, 0x8ee201a4, 0x8ee20608, 0xac62001c,
-0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
-0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400033, 0x24050001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c820000, 0x1448001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007,
-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
-0x0, 0x8004396, 0x0, 0x14600005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
-0xac800000, 0x80043a9, 0x0, 0x8ee24e30,
-0x24420001, 0x50470003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0xac880000, 0xac8a0004,
-0x54a00006, 0x240b0001, 0x8f820054, 0x1221023,
-0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
-0x24020001, 0x54620003, 0xafa00010, 0x80043d6,
-0x0, 0x3c040001, 0x24845a20, 0xafa00014,
-0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
-0x34a5f011, 0x80043d6, 0x0, 0x3c040001,
-0x24845a2c, 0xafa00014, 0x8f860120, 0x8f870124,
-0x3c050009, 0xc002403, 0x34a5f010, 0x80043d6,
-0x0, 0x3c040001, 0x24845a38, 0xafa00014,
-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
-0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac,
-0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c,
-0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028,
-0x3c020001, 0x8c425cd8, 0x27bdffe0, 0x1440000d,
-0xafbf0018, 0x3c040001, 0x24845a44, 0x3c050008,
-0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499,
-0x24020001, 0x3c010001, 0xac225cd8, 0xc002403,
-0x3821, 0x8ee204d0, 0x3c030001, 0x771821,
-0x946383b2, 0x34420001, 0x10600007, 0xaee204d0,
-0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
-0x34420008, 0xaf820220, 0x2021, 0xc0052a2,
-0x24050004, 0xaf420268, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x3c120001,
-0x26521200, 0x3c140001, 0x8e945c50, 0x3c100001,
-0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000,
-0x8eb30000, 0x26a400b, 0x248000a, 0x200f821,
-0x0, 0xd, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x80014d6,
-0x0, 0x80014d8, 0x3c0a0001, 0x80014d8,
-0x3c0a0002, 0x80014d8, 0x0, 0x80024a6,
-0x0, 0x80014d8, 0x3c0a0003, 0x80014d8,
-0x3c0a0004, 0x8002f8c, 0x0, 0x80014d8,
-0x3c0a0005, 0x8003ce8, 0x0, 0x8003c66,
-0x0, 0x80014d8, 0x3c0a0006, 0x80014d8,
-0x3c0a0007, 0x80014d8, 0x0, 0x80014d8,
-0x0, 0x80014d8, 0x0, 0x8002a75,
-0x0, 0x80014d8, 0x3c0a000b, 0x80014d8,
-0x3c0a000c, 0x80014d8, 0x3c0a000d, 0x800237a,
-0x0, 0x8002339, 0x0, 0x80014d8,
-0x3c0a000e, 0x8001b3c, 0x0, 0x80024a4,
-0x0, 0x80014d8, 0x3c0a000f, 0x80040a7,
-0x0, 0x8004091, 0x0, 0x80014d8,
-0x3c0a0010, 0x80014ee, 0x0, 0x80014d8,
-0x3c0a0011, 0x80014d8, 0x3c0a0012, 0x80014d8,
-0x3c0a0013, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x3c030001,
-0x34633800, 0x24050080, 0x2404001f, 0x2406ffff,
-0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220,
-0x3631021, 0xaf8200c0, 0x3631021, 0xaf8200c4,
-0x3631021, 0xaf8200c8, 0x27623800, 0xaf8200d0,
-0x27623800, 0xaf8200d4, 0x27623800, 0xaf8200d8,
-0x27621800, 0xaf8200e0, 0x27621800, 0xaf8200e4,
-0x27621800, 0xaf8200e8, 0x27621000, 0xaf8200f0,
-0x27621000, 0xaf8200f4, 0x27621000, 0xaf8200f8,
-0xaca00000, 0x2484ffff, 0x1486fffd, 0x24a50004,
-0x8f830040, 0x3c02f000, 0x621824, 0x3c025000,
-0x1062000c, 0x43102b, 0x14400006, 0x3c026000,
-0x3c024000, 0x10620008, 0x24020800, 0x8004539,
-0x0, 0x10620004, 0x24020800, 0x8004539,
-0x0, 0x24020700, 0x3c010001, 0xac225cdc,
-0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
-0xafb00020, 0x8f830054, 0x8f820054, 0x3c010001,
-0xac205cc4, 0x8004545, 0x24630064, 0x8f820054,
-0x621023, 0x2c420065, 0x1440fffc, 0x0,
-0xc004d71, 0x0, 0x24040001, 0x2821,
-0x27a60018, 0x34028000, 0xc00498e, 0xa7a20018,
-0x8f830054, 0x8f820054, 0x8004556, 0x24630064,
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
-0x24040001, 0x24050001, 0xc00494c, 0x27a60018,
-0x8f830054, 0x8f820054, 0x8004562, 0x24630064,
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
-0x24040001, 0x24050001, 0xc00494c, 0x27a60018,
-0x8f830054, 0x8f820054, 0x800456e, 0x24630064,
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
-0x24040001, 0x3c060001, 0x24c65da0, 0xc00494c,
-0x24050002, 0x8f830054, 0x8f820054, 0x800457b,
-0x24630064, 0x8f820054, 0x621023, 0x2c420065,
-0x1440fffc, 0x24040001, 0x24050003, 0x3c100001,
-0x26105da2, 0xc00494c, 0x2003021, 0x97a60018,
-0x3c070001, 0x94e75da0, 0x3c040001, 0x24845ab0,
-0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100,
-0xc002403, 0xafa20010, 0x97a20018, 0x1040004c,
-0x24036040, 0x96020000, 0x3042fff0, 0x1443000a,
-0x24020020, 0x3c030001, 0x94635da0, 0x54620009,
-0x24027830, 0x24020003, 0x3c010001, 0xac225cc4,
-0x80045ac, 0x24020005, 0x3c030001, 0x94635da0,
-0x24027830, 0x1462000f, 0x24030010, 0x3c020001,
-0x94425da2, 0x3042fff0, 0x1443000a, 0x24020003,
-0x3c010001, 0xac225cc4, 0x24020006, 0x3c010001,
-0xac225db0, 0x3c010001, 0xac225dbc, 0x80045e6,
-0x3c09fff0, 0x3c020001, 0x8c425cc4, 0x3c030001,
-0x94635da0, 0x34420001, 0x3c010001, 0xac225cc4,
-0x24020015, 0x1462000f, 0x0, 0x3c020001,
-0x94425da2, 0x3042fff0, 0x3843f420, 0x2c630001,
-0x3842f430, 0x2c420001, 0x621825, 0x10600005,
-0x24020003, 0x3c010001, 0xac225dbc, 0x80045e6,
-0x3c09fff0, 0x3c030001, 0x94635da0, 0x24027810,
-0x1462000b, 0x24020002, 0x3c020001, 0x94425da2,
-0x3042fff0, 0x14400006, 0x24020002, 0x24020004,
-0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0,
-0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0,
-0x3c020001, 0x8c425cc4, 0x24030001, 0x3c010001,
-0xac235dbc, 0x34420004, 0x3c010001, 0xac225cc4,
-0x3c09fff0, 0x3529bdc0, 0x3c060001, 0x8cc65cc4,
-0x3c040001, 0x24845ab0, 0x24020001, 0x3c010001,
-0xac225ccc, 0x8f820054, 0x3c070001, 0x8ce75dbc,
-0x3c030001, 0x94635da0, 0x3c080001, 0x95085da2,
-0x3c05000d, 0x34a50100, 0x3c010001, 0xac205cc8,
-0x491021, 0x3c010001, 0xac225dac, 0xafa30010,
-0xc002403, 0xafa80014, 0x8fbf0024, 0x8fb00020,
-0x3e00008, 0x27bd0028, 0x27bdffe8, 0x3c050001,
-0x8ca55cc8, 0x24060004, 0x24020001, 0x14a20014,
-0xafbf0010, 0x3c020001, 0x8c427e3c, 0x30428000,
-0x10400005, 0x3c04000f, 0x3c030001, 0x8c635dbc,
-0x8004617, 0x34844240, 0x3c040004, 0x3c030001,
-0x8c635dbc, 0x348493e0, 0x24020005, 0x14620016,
-0x0, 0x3c04003d, 0x800462f, 0x34840900,
-0x3c020001, 0x8c427e38, 0x30428000, 0x10400005,
-0x3c04001e, 0x3c030001, 0x8c635dbc, 0x800462a,
-0x34848480, 0x3c04000f, 0x3c030001, 0x8c635dbc,
-0x34844240, 0x24020005, 0x14620003, 0x0,
-0x3c04007a, 0x34841200, 0x3c020001, 0x8c425dac,
-0x8f830054, 0x441021, 0x431023, 0x44102b,
-0x14400037, 0x0, 0x3c020001, 0x8c425cd0,
-0x14400033, 0x0, 0x3c010001, 0x10c00025,
-0xac205ce0, 0x3c090001, 0x8d295cc4, 0x24070001,
-0x3c044000, 0x3c080001, 0x25087e3c, 0x250afffc,
-0x52842, 0x14a00002, 0x24c6ffff, 0x24050008,
-0xa91024, 0x10400010, 0x0, 0x14a70008,
-0x0, 0x8d020000, 0x441024, 0x1040000a,
-0x0, 0x3c010001, 0x800465b, 0xac255ce0,
-0x8d420000, 0x441024, 0x10400003, 0x0,
-0x3c010001, 0xac275ce0, 0x3c020001, 0x8c425ce0,
-0x6182b, 0x2c420001, 0x431024, 0x5440ffe5,
-0x52842, 0x8f820054, 0x3c030001, 0x8c635ce0,
-0x3c010001, 0xac225dac, 0x1060002a, 0x24020001,
-0x3c010001, 0xac255cc8, 0x3c010001, 0xac225ccc,
-0x3c020001, 0x8c425ce0, 0x10400022, 0x0,
-0x3c020001, 0x8c425ccc, 0x1040000a, 0x24020001,
-0x3c010001, 0xac205ccc, 0x3c010001, 0x370821,
-0xac2283ac, 0x3c010001, 0xac205d4c, 0x3c010001,
-0xac225d04, 0x3c030001, 0x771821, 0x8c6383ac,
-0x24020008, 0x10620005, 0x24020001, 0xc004695,
-0x0, 0x8004692, 0x0, 0x3c030001,
-0x8c635cc8, 0x10620007, 0x2402000e, 0x3c030001,
-0x8c637dd0, 0x10620003, 0x0, 0xc004e54,
-0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018,
-0x27bdffe0, 0x3c02fdff, 0xafbf0018, 0x8ee30000,
-0x3c050001, 0x8ca55cc8, 0x3c040001, 0x8c845cf0,
-0x3442ffff, 0x621824, 0x14a40008, 0xaee30000,
-0x3c030001, 0x771821, 0x8c6383ac, 0x3c020001,
-0x8c425cf4, 0x10620008, 0x0, 0x3c020001,
-0x571021, 0x8c4283ac, 0x3c010001, 0xac255cf0,
-0x3c010001, 0xac225cf4, 0x3c030001, 0x8c635cc8,
-0x24020002, 0x10620169, 0x2c620003, 0x10400005,
-0x24020001, 0x10620008, 0x0, 0x800481c,
-0x0, 0x24020004, 0x106200b1, 0x24020001,
-0x800481d, 0x0, 0x3c020001, 0x571021,
-0x8c4283ac, 0x2443ffff, 0x2c620008, 0x1040015a,
-0x31080, 0x3c010001, 0x220821, 0x8c225ac8,
-0x400008, 0x0, 0x3c030001, 0x8c635dbc,
-0x24020005, 0x14620014, 0x0, 0x3c020001,
-0x8c425cd4, 0x1040000a, 0x24020003, 0xc004822,
-0x0, 0x24020002, 0x3c010001, 0x370821,
-0xac2283ac, 0x3c010001, 0x80046e0, 0xac205cd4,
-0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
-0x800481f, 0xac205c60, 0xc004822, 0x0,
-0x3c020001, 0x8c425cd4, 0x3c010001, 0xac205c60,
-0x104000dd, 0x24020002, 0x3c010001, 0x370821,
-0xac2283ac, 0x3c010001, 0x800481f, 0xac205cd4,
-0x3c030001, 0x8c635dbc, 0x24020005, 0x14620003,
-0x24020001, 0x3c010001, 0xac225d00, 0xc0049cf,
-0x0, 0x3c030001, 0x8c635d00, 0x800478e,
-0x24020011, 0x3c050001, 0x8ca55cc8, 0x3c060001,
-0x8cc67e3c, 0xc005108, 0x2021, 0x24020005,
-0x3c010001, 0xac205cd4, 0x3c010001, 0x370821,
-0x800481f, 0xac2283ac, 0x3c040001, 0x24845abc,
-0x3c05000f, 0x34a50100, 0x3021, 0x3821,
-0xafa00010, 0xc002403, 0xafa00014, 0x800481f,
-0x0, 0x8f820220, 0x3c03f700, 0x431025,
-0x80047b7, 0xaf820220, 0x8f820220, 0x3c030004,
-0x431024, 0x144000a9, 0x24020007, 0x8f830054,
-0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023,
-0x2c422710, 0x144000f8, 0x24020001, 0x800481d,
-0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
-0x2021, 0xc005386, 0x2021, 0x3c030001,
-0x8c637e34, 0x46100ea, 0x24020001, 0x3c020008,
-0x621024, 0x10400006, 0x0, 0x8f820214,
-0x3c03ffff, 0x431024, 0x8004741, 0x3442251f,
-0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f,
-0xaf820214, 0x8ee20000, 0x3c030200, 0x431025,
-0xaee20000, 0x8f820220, 0x2403fffb, 0x431024,
-0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
-0x24020008, 0x3c010001, 0x370821, 0xac2283ac,
-0x8f820220, 0x3c030004, 0x431024, 0x14400005,
-0x0, 0x8f820220, 0x3c03f700, 0x431025,
-0xaf820220, 0x3c030001, 0x8c635dbc, 0x24020005,
-0x1462000a, 0x0, 0x3c020001, 0x94425da2,
-0x24429fbc, 0x2c420004, 0x10400004, 0x24040018,
-0x24050002, 0xc004d93, 0x24060020, 0xc0043dd,
-0x0, 0x3c010001, 0x800481f, 0xac205d50,
-0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff,
-0x2c620008, 0x104000ac, 0x31080, 0x3c010001,
-0x220821, 0x8c225ae8, 0x400008, 0x0,
-0xc00429b, 0x0, 0x3c010001, 0xac205ccc,
-0xaf800204, 0x3c010001, 0xc004822, 0xac207e20,
-0x24020001, 0x3c010001, 0xac225ce4, 0x24020002,
-0x3c010001, 0x370821, 0x800481f, 0xac2283ac,
-0xc00489f, 0x0, 0x3c030001, 0x8c635ce4,
-0x24020009, 0x14620090, 0x24020003, 0x3c010001,
-0x370821, 0x800481f, 0xac2283ac, 0x3c020001,
-0x8c427e38, 0x30424000, 0x10400005, 0x0,
-0x8f820044, 0x3c03ffff, 0x800479f, 0x34637fff,
-0x8f820044, 0x2403ff7f, 0x431024, 0xaf820044,
-0x8f830054, 0x80047b9, 0x24020004, 0x8f830054,
-0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023,
-0x2c422710, 0x14400074, 0x24020005, 0x3c010001,
-0x370821, 0x800481f, 0xac2283ac, 0x8f820220,
-0x3c03f700, 0x431025, 0xaf820220, 0xaf800204,
-0x3c010001, 0xac207e20, 0x8f830054, 0x24020006,
-0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
-0x800481f, 0xac235da4, 0x8f830054, 0x3c020001,
-0x8c425da4, 0x2463fff6, 0x431023, 0x2c42000a,
-0x14400059, 0x0, 0x24020007, 0x3c010001,
-0x370821, 0x800481f, 0xac2283ac, 0x8f820220,
-0x3c04f700, 0x441025, 0xaf820220, 0x8f820220,
-0x3c030300, 0x431024, 0x14400005, 0x1821,
-0x8f820220, 0x24030001, 0x441025, 0xaf820220,
-0x10600043, 0x24020001, 0x8f820214, 0x3c03ffff,
-0x3c040001, 0x8c845d98, 0x431024, 0x3442251f,
-0xaf820214, 0x24020008, 0x3c010001, 0x370821,
-0x1080000b, 0xac2283ac, 0x3c020001, 0x8c425d74,
-0x14400007, 0x24020001, 0x3c010001, 0xac227dd0,
-0xc004e54, 0x8f840220, 0x800480c, 0x0,
-0x8f820220, 0x3c030008, 0x431024, 0x14400017,
-0x2402000e, 0x3c010001, 0xac227dd0, 0x8ee20000,
-0x2021, 0x3c030200, 0x431025, 0xc005386,
-0xaee20000, 0x8f820220, 0x2403fffb, 0x431024,
-0xaf820220, 0x8f820220, 0x34420002, 0xc0043dd,
-0xaf820220, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
-0x2021, 0x800481f, 0x0, 0x3c020001,
-0x8c425d74, 0x10400010, 0x0, 0x3c020001,
-0x8c425d70, 0x2442ffff, 0x3c010001, 0xac225d70,
-0x14400009, 0x24020002, 0x3c010001, 0xac205d74,
-0x3c010001, 0x800481f, 0xac225d70, 0x24020001,
-0x3c010001, 0xac225ccc, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220,
-0x34420004, 0xaf820220, 0x8f820200, 0x3c060001,
-0x8cc65cc8, 0x34420004, 0xaf820200, 0x24020002,
-0x10c2003a, 0x2cc20003, 0x10400005, 0x24020001,
-0x10c20008, 0x0, 0x8004868, 0x0,
-0x24020004, 0x10c20013, 0x24020001, 0x8004868,
-0x0, 0x3c030001, 0x8c635cb8, 0x3c020001,
-0x8c425cc0, 0x3c040001, 0x8c845cdc, 0x3c050001,
-0x8ca55cbc, 0xaf860200, 0xaf860220, 0x34630022,
-0x441025, 0x451025, 0x34420002, 0x8004867,
-0xaf830200, 0x3c030001, 0x8c635d98, 0xaf820200,
-0x10600009, 0xaf820220, 0x3c020001, 0x8c425d74,
-0x14400005, 0x3c033f00, 0x3c020001, 0x8c425cb0,
-0x800485b, 0x346300e0, 0x3c020001, 0x8c425cb0,
-0x3c033f00, 0x346300e2, 0x431025, 0xaf820200,
-0x3c030001, 0x8c635cb4, 0x3c04f700, 0x3c020001,
-0x8c425cc0, 0x3c050001, 0x8ca55cdc, 0x641825,
-0x431025, 0x451025, 0xaf820220, 0x3e00008,
-0x0, 0x8f820220, 0x3c030001, 0x8c635cc8,
-0x34420004, 0xaf820220, 0x24020001, 0x1062000f,
-0x0, 0x8f830054, 0x8f820054, 0x24630002,
-0x621023, 0x2c420003, 0x10400011, 0x0,
-0x8f820054, 0x621023, 0x2c420003, 0x1040000c,
-0x0, 0x8004879, 0x0, 0x8f830054,
-0x8f820054, 0x8004885, 0x24630007, 0x8f820054,
-0x621023, 0x2c420008, 0x1440fffc, 0x0,
-0x8f8400e0, 0x30820007, 0x1040000d, 0x0,
-0x8f820054, 0x8f8300e0, 0x14830009, 0x24450032,
-0x8f820054, 0xa21023, 0x2c420033, 0x10400004,
-0x0, 0x8f8200e0, 0x1082fff9, 0x0,
-0x8f820220, 0x2403fffd, 0x431024, 0xaf820220,
-0x3e00008, 0x0, 0x3c030001, 0x8c635ce4,
-0x3c020001, 0x8c425ce8, 0x50620004, 0x2463ffff,
-0x3c010001, 0xac235ce8, 0x2463ffff, 0x2c620009,
-0x1040009d, 0x31080, 0x3c010001, 0x220821,
-0x8c225b08, 0x400008, 0x0, 0x8f820044,
-0x34428080, 0xaf820044, 0x8f830054, 0x8004938,
-0x24020002, 0x8f830054, 0x3c020001, 0x8c425da8,
-0x2463d8f0, 0x431023, 0x2c422710, 0x1440008a,
-0x24020003, 0x8004945, 0x0, 0x8f820044,
-0x3c03ffff, 0x34637fff, 0x431024, 0xaf820044,
-0x8f830054, 0x8004938, 0x24020004, 0x8f830054,
-0x3c020001, 0x8c425da8, 0x2463fff6, 0x431023,
-0x2c42000a, 0x14400078, 0x24020005, 0x8004945,
-0x0, 0x8f820220, 0x3c03f700, 0x431025,
-0xaf820220, 0x8f820220, 0x2403fffb, 0x431024,
-0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
-0x3c023f00, 0x344200e0, 0xaf820200, 0x8f820200,
-0x2403fffd, 0x431024, 0xaf820200, 0x24040001,
-0x3405ffff, 0xaf840204, 0x8f830054, 0x8f820054,
-0x80048ec, 0x24630001, 0x8f820054, 0x621023,
-0x2c420002, 0x1440fffc, 0x0, 0x8f820224,
-0x42040, 0xa4102b, 0x1040fff2, 0x0,
-0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
-0x8f820214, 0x3c03ffff, 0x431024, 0x3442251f,
-0xaf820214, 0x8f820220, 0x2403fffb, 0x431024,
-0xaf820220, 0x8f820220, 0x3c04f700, 0x34840008,
-0x34420002, 0xaf820220, 0x8f820220, 0x3c033f00,
-0x346300e2, 0x441025, 0xaf820220, 0xaf830200,
-0x8f8400f0, 0x276217f8, 0x14820002, 0x24850008,
-0x27651000, 0x8f8200f4, 0x10a20007, 0x3c038000,
-0x34630040, 0x3c020001, 0x24425c70, 0xac820000,
-0xac830004, 0xaf8500f0, 0x8f830054, 0x8004938,
-0x24020006, 0x8f830054, 0x3c020001, 0x8c425da8,
-0x2463fff6, 0x431023, 0x2c42000a, 0x14400022,
-0x24020007, 0x8004945, 0x0, 0x8f8200e0,
-0xaf8200e4, 0x8f8200e0, 0xaf8200e8, 0x8f820220,
-0x34420004, 0xaf820220, 0x8f820220, 0x2403fff7,
-0x431024, 0xaf820220, 0x8f820044, 0x34428080,
-0xaf820044, 0x8f830054, 0x24020008, 0x3c010001,
-0xac225ce4, 0x3c010001, 0x8004947, 0xac235da8,
-0x8f830054, 0x3c020001, 0x8c425da8, 0x2463d8f0,
-0x431023, 0x2c422710, 0x14400003, 0x24020009,
-0x3c010001, 0xac225ce4, 0x3e00008, 0x0,
-0x0, 0x0, 0x0, 0x27bdffd8,
-0xafb20018, 0x809021, 0xafb3001c, 0xa09821,
-0xafb10014, 0xc08821, 0xafb00010, 0x8021,
-0xafbf0020, 0xa6200000, 0xc004d4b, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d4b, 0x2021, 0xc004d4b, 0x24040001,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x24100010, 0x2501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d4b, 0x108042, 0x1600fffa,
-0x2501024, 0x24100010, 0x2701024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x2701024, 0xc004d71, 0x34108000,
-0xc004d71, 0x0, 0xc004d2b, 0x0,
-0x50400005, 0x108042, 0x96220000, 0x501025,
-0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004d71, 0x0, 0x8fbf0020, 0x8fb3001c,
-0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008,
-0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821,
-0xafb20018, 0xa09021, 0xafb3001c, 0xc09821,
-0xafb00010, 0x8021, 0xafbf0020, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0x24100010, 0x2301024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x2301024, 0x24100010, 0x2501024,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x2501024, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
-0x96620000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
-0x0, 0xc004d71, 0x0, 0x8fbf0020,
-0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
-0x3e00008, 0x27bd0028, 0x3c030001, 0x8c635d00,
-0x3c020001, 0x8c425d48, 0x27bdffd8, 0xafbf0020,
-0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001,
-0xac235d48, 0x2463ffff, 0x2c620013, 0x10400349,
-0x31080, 0x3c010001, 0x220821, 0x8c225b30,
-0x400008, 0x0, 0xc004d71, 0x8021,
-0x34028000, 0xa7a20010, 0x27b10010, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0xc004d4b,
-0x2021, 0x108042, 0x1600fffc, 0x0,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fff8, 0x0, 0xc004d71, 0x0,
-0x8004d24, 0x24020002, 0x27b10010, 0xa7a00010,
-0x8021, 0xc004d4b, 0x24040001, 0x26100001,
-0x2e020020, 0x1440fffb, 0x0, 0xc004d4b,
-0x2021, 0xc004d4b, 0x24040001, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0x24100010,
-0x32020001, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020001,
-0x24100010, 0xc004d4b, 0x2021, 0x108042,
-0x1600fffc, 0x0, 0xc004d71, 0x34108000,
-0xc004d71, 0x0, 0xc004d2b, 0x0,
-0x50400005, 0x108042, 0x96220000, 0x501025,
-0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004d71, 0x0, 0x97a20010, 0x30428000,
-0x144002dc, 0x24020003, 0x8004d24, 0x0,
-0x24021200, 0xa7a20010, 0x27b10010, 0x8021,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0xc004d4b, 0x2021, 0x108042, 0x1600fffc,
-0x0, 0xc004d4b, 0x24040001, 0xc004d4b,
-0x2021, 0x34108000, 0x96220000, 0x501024,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fff8, 0x0, 0xc004d71,
-0x0, 0x8f830054, 0x8004d16, 0x24020004,
-0x8f830054, 0x3c020001, 0x8c425db8, 0x2463ff9c,
-0x431023, 0x2c420064, 0x1440029e, 0x24020002,
-0x3c030001, 0x8c635dbc, 0x10620297, 0x2c620003,
-0x14400296, 0x24020011, 0x24020003, 0x10620005,
-0x24020004, 0x10620291, 0x2402000f, 0x8004d24,
-0x24020011, 0x8004d24, 0x24020005, 0x24020014,
-0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x32020012,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020012, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
-0x96220000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
-0x0, 0xc004d71, 0x0, 0x8f830054,
-0x8004d16, 0x24020006, 0x8f830054, 0x3c020001,
-0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064,
-0x14400250, 0x24020007, 0x8004d24, 0x0,
-0x24020006, 0xa7a20010, 0x27b10010, 0x8021,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020013, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020013,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fff8, 0x0, 0xc004d71, 0x0,
-0x8f830054, 0x8004d16, 0x24020008, 0x8f830054,
-0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
-0x2c420064, 0x1440020f, 0x24020009, 0x8004d24,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
-0xc004d4b, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
-0xc004d71, 0x34108000, 0xc004d71, 0x0,
-0xc004d2b, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004d71, 0x8021,
-0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fff8, 0x0, 0xc004d71, 0x0,
-0x8f830054, 0x8004d16, 0x2402000a, 0x8f830054,
-0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
-0x2c420064, 0x1440019b, 0x2402000b, 0x8004d24,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
-0xc004d4b, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020017, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020017,
-0xc004d71, 0x34108000, 0xc004d71, 0x0,
-0xc004d2b, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004d71, 0x8021,
-0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020017, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020017,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fff8, 0x0, 0xc004d71, 0x0,
-0x8f830054, 0x8004d16, 0x2402000c, 0x8f830054,
-0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
-0x2c420064, 0x14400127, 0x24020012, 0x8004d24,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
-0xc004d4b, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020014, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020014,
-0xc004d71, 0x34108000, 0xc004d71, 0x0,
-0xc004d2b, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004d71, 0x8021,
-0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020014, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020014,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fff8, 0x0, 0xc004d71, 0x0,
-0x8f830054, 0x8004d16, 0x24020013, 0x8f830054,
-0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
-0x2c420064, 0x144000b3, 0x2402000d, 0x8004d24,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
-0xc004d4b, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
-0xc004d71, 0x34108000, 0xc004d71, 0x0,
-0xc004d2b, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004d71, 0x8021,
-0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fff8, 0x0, 0xc004d71, 0x0,
-0x8f830054, 0x8004d16, 0x2402000e, 0x24020840,
-0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x32020013,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020013, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
-0x96220000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
-0x0, 0xc004d71, 0x0, 0x8f830054,
-0x24020010, 0x3c010001, 0xac225d00, 0x3c010001,
-0x8004d26, 0xac235db8, 0x8f830054, 0x3c020001,
-0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064,
-0x14400004, 0x0, 0x24020011, 0x3c010001,
-0xac225d00, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
-0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044,
-0x3c030001, 0x431025, 0x3c030008, 0xaf820044,
-0x8f840054, 0x8f820054, 0xa32824, 0x8004d37,
-0x24840001, 0x8f820054, 0x821023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
-0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
-0x8f820054, 0x8004d45, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0,
-0x3442ffff, 0x42480, 0x621824, 0x3c020002,
-0x822025, 0x641825, 0xaf830044, 0x8f820044,
-0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
-0x8f830054, 0x8f820054, 0x8004d5e, 0x24630001,
-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
-0x0, 0x8f820044, 0x3c030001, 0x431025,
-0xaf820044, 0x8f830054, 0x8f820054, 0x8004d6b,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x3e00008, 0x0,
-0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024,
-0xaf820044, 0x8f820044, 0x3c030001, 0x431025,
-0xaf820044, 0x8f830054, 0x8f820054, 0x8004d7f,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
-0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
-0x8f820054, 0x8004d8d, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
-0x809821, 0xafb5002c, 0xa0a821, 0xafb20020,
-0xc09021, 0x32a2ffff, 0xafbf0030, 0xafb40028,
-0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010,
-0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x2301024, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
-0x96420000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d4b, 0x108042, 0x12000075,
-0x0, 0x8004dc9, 0x0, 0x3274ffff,
-0x27b10010, 0xa7a00010, 0x8021, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x24040001, 0xc004d4b,
-0x2021, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x2901024,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x2901024, 0xc004d71,
-0x34108000, 0xc004d71, 0x0, 0xc004d2b,
-0x0, 0x50400005, 0x108042, 0x96220000,
-0x501025, 0xa6220000, 0x108042, 0x1600fff7,
-0x0, 0xc004d71, 0x0, 0x32a5ffff,
-0x24020001, 0x54a20004, 0x24020002, 0x97a20010,
-0x8004e14, 0x521025, 0x14a20006, 0x3271ffff,
-0x97a20010, 0x121827, 0x431024, 0xa7a20010,
-0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x2301024, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
-0x96420000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
-0x0, 0xc004d71, 0x0, 0x8fbf0030,
-0x8fb5002c, 0x8fb40028, 0x8fb30024, 0x8fb20020,
-0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038,
-0x0, 0x0, 0x0, 0x27bdffe8,
-0xafbf0010, 0x3c030001, 0x771821, 0x8c6383ac,
-0x24020008, 0x1462022c, 0x803021, 0x3c020001,
-0x8c425d98, 0x14400033, 0x0, 0x8f850224,
-0x38a30020, 0x2c630001, 0x38a20010, 0x2c420001,
-0x621825, 0x1460000d, 0x38a30030, 0x2c630001,
-0x38a20400, 0x2c420001, 0x621825, 0x14600007,
-0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001,
-0x621825, 0x10600005, 0x0, 0xc00429b,
-0x0, 0x8004e8d, 0x2402000e, 0xc0043dd,
-0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
-0x2021, 0x3c030001, 0x8c635cc8, 0x24020004,
-0x14620005, 0x2403fffb, 0x3c020001, 0x8c425cc4,
-0x8004e89, 0x2403fff7, 0x3c020001, 0x8c425cc4,
-0x431024, 0x3c010001, 0xac225cc4, 0x2402000e,
-0x3c010001, 0xc00429b, 0xac227dd0, 0x8005087,
-0x0, 0x8f820220, 0x3c030400, 0x431024,
-0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001,
-0x8c427ddc, 0xa32024, 0x431024, 0x1482000c,
-0x0, 0x3c020001, 0x8c427de0, 0x24420001,
-0x3c010001, 0xac227de0, 0x2c420002, 0x14400008,
-0x24020001, 0x3c010001, 0x8004ead, 0xac227e00,
-0x3c010001, 0xac207de0, 0x3c010001, 0xac207e00,
-0x3c020001, 0x8c427e00, 0x10400006, 0x30a20040,
-0x10400004, 0x24020001, 0x3c010001, 0x8004eb8,
-0xac227e04, 0x3c010001, 0xac207e04, 0x3c010001,
-0xac257ddc, 0x3c010001, 0x8004ec8, 0xac207e10,
-0x24020001, 0x3c010001, 0xac227e10, 0x3c010001,
-0xac207e00, 0x3c010001, 0xac207de0, 0x3c010001,
-0xac207e04, 0x3c010001, 0xac207ddc, 0x3c030001,
-0x8c637dd0, 0x3c020001, 0x8c427dd4, 0x10620003,
-0x3c020200, 0x3c010001, 0xac237dd4, 0xc21024,
-0x10400007, 0x2463ffff, 0x8f820220, 0x24030001,
-0x3c010001, 0xac235ccc, 0x8005085, 0x3c03f700,
-0x2c62000e, 0x104001a8, 0x31080, 0x3c010001,
-0x220821, 0x8c225b80, 0x400008, 0x0,
-0x3c010001, 0xac207e00, 0x3c010001, 0xac207de0,
-0x3c010001, 0xac207ddc, 0x3c010001, 0xac207e04,
-0x3c010001, 0xac207df8, 0x3c010001, 0xac207df0,
-0xc00486a, 0xaf800224, 0x24020002, 0x3c010001,
-0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400056,
-0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
-0xc00429b, 0xaee20000, 0xaf800204, 0x8f820200,
-0x2403fffd, 0x431024, 0xaf820200, 0x3c010001,
-0xac207e20, 0x8f830054, 0x3c020001, 0x8c427df8,
-0x24040001, 0x3c010001, 0xac247e0c, 0x24420001,
-0x3c010001, 0xac227df8, 0x2c420004, 0x3c010001,
-0xac237df4, 0x14400006, 0x24020003, 0x3c010001,
-0xac245ccc, 0x3c010001, 0x8005083, 0xac207df8,
-0x3c010001, 0x8005083, 0xac227dd0, 0x8f830054,
-0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023,
-0x2c422710, 0x14400003, 0x24020004, 0x3c010001,
-0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400026,
-0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
-0x8005083, 0xaee20000, 0x3c040001, 0x8c845d9c,
-0x3c010001, 0xc00508a, 0xac207de8, 0x3c020001,
-0x8c427e1c, 0xaf820204, 0x3c020001, 0x8c427e10,
-0x14400015, 0x3c03fdff, 0x8ee20000, 0x3463ffff,
-0x431024, 0xaee20000, 0x8f820204, 0x30420030,
-0x1440013c, 0x24020002, 0x3c030001, 0x8c637e1c,
-0x24020005, 0x3c010001, 0xac227dd0, 0x3c010001,
-0x8005083, 0xac237e20, 0x3c020001, 0x8c427e10,
-0x10400010, 0x3c03fdff, 0x3c020001, 0x8c425d6c,
-0x24420001, 0x3c010001, 0xac225d6c, 0x2c420002,
-0x14400131, 0x24020001, 0x3c010001, 0xac225d74,
-0x3c010001, 0xac205d6c, 0x3c010001, 0x8005083,
-0xac225ccc, 0x8ee20000, 0x3463ffff, 0x431024,
-0xaee20000, 0x3c020001, 0x8c427e00, 0x10400122,
-0x0, 0x3c020001, 0x8c427ddc, 0x1040011e,
-0x0, 0x3c010001, 0xac227e08, 0x24020003,
-0x3c010001, 0xac227de0, 0x8005024, 0x24020006,
-0x3c010001, 0xac207de8, 0x8f820204, 0x34420040,
-0xaf820204, 0x3c020001, 0x8c427e20, 0x24030007,
-0x3c010001, 0xac237dd0, 0x34420040, 0x3c010001,
-0xac227e20, 0x3c020001, 0x8c427e00, 0x10400005,
-0x0, 0x3c020001, 0x8c427ddc, 0x104000f9,
-0x24020002, 0x3c050001, 0x24a57de0, 0x8ca20000,
-0x2c424e21, 0x104000f3, 0x24020002, 0x3c020001,
-0x8c427e04, 0x104000f8, 0x2404ffbf, 0x3c020001,
-0x8c427ddc, 0x3c030001, 0x8c637e08, 0x441024,
-0x641824, 0x10430004, 0x24020001, 0x3c010001,
-0x8005083, 0xac227dd0, 0x24020003, 0xaca20000,
-0x24020008, 0x3c010001, 0xac227dd0, 0x3c020001,
-0x8c427e0c, 0x1040000c, 0x24020001, 0x3c040001,
-0xc005097, 0x8c847ddc, 0x3c020001, 0x8c427e28,
-0x14400005, 0x24020001, 0x3c020001, 0x8c427e24,
-0x10400006, 0x24020001, 0x3c010001, 0xac225ccc,
-0x3c010001, 0x8005083, 0xac207df8, 0x3c020001,
-0x8c427df0, 0x3c030001, 0x8c637ddc, 0x2c420001,
-0x210c0, 0x30630008, 0x3c010001, 0xac227df0,
-0x3c010001, 0xac237dec, 0x8f830054, 0x24020009,
-0x3c010001, 0xac227dd0, 0x3c010001, 0x8005083,
-0xac237df4, 0x8f830054, 0x3c020001, 0x8c427df4,
-0x2463d8f0, 0x431023, 0x2c422710, 0x144000a8,
-0x0, 0x3c020001, 0x8c427e00, 0x10400005,
-0x0, 0x3c020001, 0x8c427ddc, 0x104000a9,
-0x24020002, 0x3c030001, 0x24637de0, 0x8c620000,
-0x2c424e21, 0x104000a3, 0x24020002, 0x3c020001,
-0x8c427e0c, 0x1040000e, 0x0, 0x3c020001,
-0x8c427ddc, 0x3c010001, 0xac207e0c, 0x30420080,
-0x1040002f, 0x2402000c, 0x8f820204, 0x30420080,
-0x1440000c, 0x24020003, 0x8005011, 0x2402000c,
-0x3c020001, 0x8c427ddc, 0x30420080, 0x14400005,
-0x24020003, 0x8f820204, 0x30420080, 0x1040001f,
-0x24020003, 0xac620000, 0x2402000a, 0x3c010001,
-0xac227dd0, 0x3c040001, 0x24847e18, 0x8c820000,
-0x3c030001, 0x8c637df0, 0x431025, 0xaf820204,
-0x8c830000, 0x3c040001, 0x8c847df0, 0x2402000b,
-0x3c010001, 0xac227dd0, 0x641825, 0x3c010001,
-0xac237e20, 0x3c050001, 0x24a57de0, 0x8ca20000,
-0x2c424e21, 0x1040006f, 0x24020002, 0x3c020001,
-0x8c427e10, 0x10400005, 0x0, 0x2402000c,
-0x3c010001, 0x8005083, 0xac227dd0, 0x3c020001,
-0x8c427e00, 0x1040006c, 0x0, 0x3c040001,
-0x8c847ddc, 0x1080005e, 0x30820008, 0x3c030001,
-0x8c637dec, 0x10620064, 0x24020003, 0x3c010001,
-0xac247e08, 0xaca20000, 0x24020006, 0x3c010001,
-0x8005083, 0xac227dd0, 0x8f820200, 0x34420002,
-0xaf820200, 0x8f830054, 0x2402000d, 0x3c010001,
-0xac227dd0, 0x3c010001, 0xac237df4, 0x8f830054,
-0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023,
-0x2c422710, 0x1440003a, 0x0, 0x3c020001,
-0x8c427e10, 0x10400029, 0x2402000e, 0x3c030001,
-0x8c637e24, 0x3c010001, 0x14600015, 0xac227dd0,
-0xc0043dd, 0x0, 0x3c050001, 0x8ca55cc8,
-0xc0052a2, 0x2021, 0x3c030001, 0x8c635cc8,
-0x24020004, 0x14620005, 0x2403fffb, 0x3c020001,
-0x8c425cc4, 0x8005052, 0x2403fff7, 0x3c020001,
-0x8c425cc4, 0x431024, 0x3c010001, 0xac225cc4,
-0x8ee20000, 0x3c030200, 0x431025, 0xaee20000,
-0x8f820224, 0x3c010001, 0xac227e2c, 0x8f820220,
-0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
-0x34420002, 0x8005083, 0xaf820220, 0x3c020001,
-0x8c427e00, 0x10400005, 0x0, 0x3c020001,
-0x8c427ddc, 0x1040000f, 0x24020002, 0x3c020001,
-0x8c427de0, 0x2c424e21, 0x1040000a, 0x24020002,
-0x3c020001, 0x8c427e00, 0x1040000f, 0x0,
-0x3c020001, 0x8c427ddc, 0x1440000b, 0x0,
-0x24020002, 0x3c010001, 0x8005083, 0xac227dd0,
-0x3c020001, 0x8c427e00, 0x10400003, 0x0,
-0xc00429b, 0x0, 0x8f820220, 0x3c03f700,
-0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008,
-0x27bd0018, 0x3c030001, 0x24637e28, 0x8c620000,
-0x10400005, 0x34422000, 0x3c010001, 0xac227e1c,
-0x8005095, 0xac600000, 0x3c010001, 0xac247e1c,
-0x3e00008, 0x0, 0x27bdffe0, 0x30820030,
-0xafbf0018, 0x3c010001, 0xac227e24, 0x14400067,
-0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061,
-0x24020030, 0x30822000, 0x1040005d, 0x30838000,
-0x31a02, 0x30820001, 0x21200, 0x3c040001,
-0x8c845d9c, 0x621825, 0x331c2, 0x3c030001,
-0x24635d78, 0x30828000, 0x21202, 0x30840001,
-0x42200, 0x441025, 0x239c2, 0x61080,
-0x431021, 0x471021, 0x90430000, 0x24020001,
-0x10620025, 0x0, 0x10600007, 0x24020002,
-0x10620013, 0x24020003, 0x1062002c, 0x3c05000f,
-0x80050f9, 0x0, 0x8f820200, 0x2403feff,
-0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe,
-0x3463ffff, 0x431024, 0xaf820220, 0x3c010001,
-0xac207e44, 0x3c010001, 0x8005104, 0xac207e4c,
-0x8f820200, 0x34420100, 0xaf820200, 0x8f820220,
-0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
-0x24020100, 0x3c010001, 0xac227e44, 0x3c010001,
-0x8005104, 0xac207e4c, 0x8f820200, 0x2403feff,
-0x431024, 0xaf820200, 0x8f820220, 0x3c030001,
-0x431025, 0xaf820220, 0x3c010001, 0xac207e44,
-0x3c010001, 0x8005104, 0xac237e4c, 0x8f820200,
-0x34420100, 0xaf820200, 0x8f820220, 0x3c030001,
-0x431025, 0xaf820220, 0x24020100, 0x3c010001,
-0xac227e44, 0x3c010001, 0x8005104, 0xac237e4c,
-0x34a5ffff, 0x3c040001, 0x24845bb8, 0xafa30010,
-0xc002403, 0xafa00014, 0x8005104, 0x0,
-0x24020030, 0x3c010001, 0xac227e28, 0x8fbf0018,
-0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8,
-0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
-0xafb00020, 0xc08021, 0x3c040001, 0x24845bd0,
-0x3c050009, 0x3c020001, 0x8c425cc8, 0x34a59001,
-0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
-0xa7a0001a, 0xafb00014, 0xc002403, 0xafa20010,
-0x24020002, 0x12620083, 0x2e620003, 0x10400005,
-0x24020001, 0x1262000a, 0x0, 0x800529b,
-0x0, 0x24020004, 0x126200fa, 0x24020008,
-0x126200f9, 0x3c02ffec, 0x800529b, 0x0,
-0x3c020001, 0x8c425cc4, 0x30420002, 0x14400004,
-0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
-0x3c010001, 0x310821, 0xac307e3c, 0x3c024000,
-0x2021024, 0x1040004e, 0x1023c2, 0x30840030,
-0x101382, 0x3042001c, 0x3c030001, 0x24635d08,
-0x431021, 0x823821, 0x3c020020, 0x2021024,
-0x10400006, 0x24020100, 0x3c010001, 0x310821,
-0xac227e40, 0x8005150, 0x3c020080, 0x3c010001,
-0x310821, 0xac207e40, 0x3c020080, 0x2021024,
-0x10400006, 0x121940, 0x3c020001, 0x3c010001,
-0x230821, 0x800515c, 0xac227e48, 0x121140,
-0x3c010001, 0x220821, 0xac207e48, 0x94e40000,
-0x3c030001, 0x8c635dbc, 0x24020005, 0x10620010,
-0xa7a40018, 0x32024000, 0x10400002, 0x34824000,
-0xa7a20018, 0x24040001, 0x94e20002, 0x24050004,
-0x24e60002, 0x34420001, 0xc00498e, 0xa4e20002,
-0x24040001, 0x2821, 0xc00498e, 0x27a60018,
-0x3c020001, 0x8c425cc8, 0x24110001, 0x3c010001,
-0xac315cd4, 0x14530004, 0x32028000, 0xc00429b,
-0x0, 0x32028000, 0x1040011f, 0x0,
-0xc00429b, 0x0, 0x3c030001, 0x8c635dbc,
-0x24020005, 0x10620118, 0x24020002, 0x3c010001,
-0xac315ccc, 0x3c010001, 0x800529b, 0xac225cc8,
-0x24040001, 0x24050004, 0x27b0001a, 0xc00498e,
-0x2003021, 0x24040001, 0x2821, 0xc00498e,
-0x2003021, 0x3c020001, 0x511021, 0x8c427e34,
-0x3c040001, 0x8c845cc8, 0x3c03bfff, 0x3463ffff,
-0x3c010001, 0xac335cd4, 0x431024, 0x3c010001,
-0x310821, 0x109300fa, 0xac227e34, 0x800529b,
-0x0, 0x3c022000, 0x2021024, 0x10400005,
-0x24020001, 0x3c010001, 0xac225d98, 0x80051ad,
-0x128940, 0x3c010001, 0xac205d98, 0x128940,
-0x3c010001, 0x310821, 0xac307e38, 0x3c024000,
-0x2021024, 0x14400016, 0x0, 0x3c020001,
-0x8c425d98, 0x10400008, 0x24040004, 0x24050001,
-0xc004d93, 0x24062000, 0x24020001, 0x3c010001,
-0x370821, 0xac2283ac, 0x3c020001, 0x511021,
-0x8c427e30, 0x3c03bfff, 0x3463ffff, 0x431024,
-0x3c010001, 0x310821, 0x8005299, 0xac227e30,
-0x3c020001, 0x8c425d98, 0x10400028, 0x3c0300a0,
-0x2031024, 0x5443000d, 0x3c020020, 0x3c020001,
-0x8c425d9c, 0x24030100, 0x3c010001, 0x310821,
-0xac237e44, 0x3c030001, 0x3c010001, 0x310821,
-0xac237e4c, 0x80051f0, 0x34420400, 0x2021024,
-0x10400008, 0x24030100, 0x3c020001, 0x8c425d9c,
-0x3c010001, 0x310821, 0xac237e44, 0x80051f0,
-0x34420800, 0x3c020080, 0x2021024, 0x1040002e,
-0x3c030001, 0x3c020001, 0x8c425d9c, 0x3c010001,
-0x310821, 0xac237e4c, 0x34420c00, 0x3c010001,
-0xac225d9c, 0x8005218, 0x24040001, 0x3c020020,
-0x2021024, 0x10400006, 0x24020100, 0x3c010001,
-0x310821, 0xac227e44, 0x8005201, 0x3c020080,
-0x3c010001, 0x310821, 0xac207e44, 0x3c020080,
-0x2021024, 0x10400007, 0x121940, 0x3c020001,
-0x3c010001, 0x230821, 0xac227e4c, 0x800520f,
-0x24040001, 0x121140, 0x3c010001, 0x220821,
-0xac207e4c, 0x24040001, 0x2821, 0x27b0001e,
-0xc00494c, 0x2003021, 0x24040001, 0x2821,
-0xc00494c, 0x2003021, 0x24040001, 0x24050001,
-0x27b0001c, 0xc00494c, 0x2003021, 0x24040001,
-0x24050001, 0xc00494c, 0x2003021, 0x8005299,
-0x0, 0x3c02ffec, 0x3442ffff, 0x2028024,
-0x3c020008, 0x2028025, 0x121140, 0x3c010001,
-0x220821, 0xac307e38, 0x3c022000, 0x2021024,
-0x10400009, 0x0, 0x3c020001, 0x8c425d74,
-0x14400005, 0x24020001, 0x3c010001, 0xac225d98,
-0x800523a, 0x3c024000, 0x3c010001, 0xac205d98,
-0x3c024000, 0x2021024, 0x1440001e, 0x0,
-0x3c020001, 0x8c425d98, 0x3c010001, 0xac205ce0,
-0x10400007, 0x24022020, 0x3c010001, 0xac225d9c,
-0x24020001, 0x3c010001, 0x370821, 0xac2283ac,
-0x3c04bfff, 0x121940, 0x3c020001, 0x431021,
-0x8c427e30, 0x3c050001, 0x8ca55cc8, 0x3484ffff,
-0x441024, 0x3c010001, 0x230821, 0xac227e30,
-0x24020001, 0x10a20044, 0x0, 0x8005299,
-0x0, 0x3c020001, 0x8c425d98, 0x1040001c,
-0x24022000, 0x3c010001, 0xac225d9c, 0x3c0300a0,
-0x2031024, 0x14430005, 0x121140, 0x3402a000,
-0x3c010001, 0x8005294, 0xac225d9c, 0x3c030001,
-0x621821, 0x8c637e38, 0x3c020020, 0x621024,
-0x10400004, 0x24022001, 0x3c010001, 0x8005294,
-0xac225d9c, 0x3c020080, 0x621024, 0x1040001f,
-0x3402a001, 0x3c010001, 0x8005294, 0xac225d9c,
-0x3c020020, 0x2021024, 0x10400007, 0x121940,
-0x24020100, 0x3c010001, 0x230821, 0xac227e44,
-0x8005288, 0x3c020080, 0x121140, 0x3c010001,
-0x220821, 0xac207e44, 0x3c020080, 0x2021024,
-0x10400006, 0x121940, 0x3c020001, 0x3c010001,
-0x230821, 0x8005294, 0xac227e4c, 0x121140,
-0x3c010001, 0x220821, 0xac207e4c, 0x3c030001,
-0x8c635cc8, 0x24020001, 0x10620003, 0x0,
-0xc00429b, 0x0, 0x8fbf0030, 0x8fb3002c,
-0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
-0x27bd0038, 0x27bdffd8, 0xafb20020, 0x809021,
-0xafb1001c, 0x8821, 0x24020002, 0xafbf0024,
-0xafb00018, 0xa7a00012, 0x10a200d3, 0xa7a00010,
-0x2ca20003, 0x10400005, 0x24020001, 0x10a2000a,
-0x128140, 0x8005380, 0x2201021, 0x24020004,
-0x10a2007d, 0x24020008, 0x10a2007c, 0x122940,
-0x8005380, 0x2201021, 0x3c030001, 0x701821,
-0x8c637e3c, 0x3c024000, 0x621024, 0x14400009,
-0x24040001, 0x3c027fff, 0x3442ffff, 0x628824,
-0x3c010001, 0x300821, 0xac317e34, 0x8005380,
-0x2201021, 0x24050001, 0xc00494c, 0x27a60010,
-0x24040001, 0x24050001, 0xc00494c, 0x27a60010,
-0x97a20010, 0x30420004, 0x10400034, 0x3c114000,
-0x3c020001, 0x8c425dbc, 0x2443ffff, 0x2c620006,
-0x10400034, 0x31080, 0x3c010001, 0x220821,
-0x8c225be0, 0x400008, 0x0, 0x24040001,
-0x24050011, 0x27b00012, 0xc00494c, 0x2003021,
-0x24040001, 0x24050011, 0xc00494c, 0x2003021,
-0x97a50012, 0x30a24000, 0x10400002, 0x3c040010,
-0x3c040008, 0x3c030001, 0x8005301, 0x30a28000,
-0x24040001, 0x24050014, 0x27b00012, 0xc00494c,
-0x2003021, 0x24040001, 0x24050014, 0xc00494c,
-0x2003021, 0x97a50012, 0x30a21000, 0x10400002,
-0x3c040010, 0x3c040008, 0x3c030001, 0x30a20800,
-0x54400001, 0x3c030002, 0x3c028000, 0x2221025,
-0x641825, 0x800530e, 0x438825, 0x3c110001,
-0x2308821, 0x8e317e3c, 0x3c027fff, 0x3442ffff,
-0x2228824, 0x3c020001, 0x8c425cd8, 0x1040001d,
-0x121140, 0x3c020001, 0x8c425d98, 0x10400002,
-0x3c022000, 0x2228825, 0x121140, 0x3c010001,
-0x220821, 0x8c227e40, 0x10400003, 0x3c020020,
-0x8005322, 0x2228825, 0x3c02ffdf, 0x3442ffff,
-0x2228824, 0x121140, 0x3c010001, 0x220821,
-0x8c227e48, 0x10400003, 0x3c020080, 0x800532d,
-0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824,
-0x121140, 0x3c010001, 0x220821, 0xac317e34,
-0x8005380, 0x2201021, 0x122940, 0x3c030001,
-0x651821, 0x8c637e38, 0x3c024000, 0x621024,
-0x14400008, 0x3c027fff, 0x3442ffff, 0x628824,
-0x3c010001, 0x250821, 0xac317e30, 0x8005380,
-0x2201021, 0x3c020001, 0x8c425cd8, 0x10400033,
-0x3c11c00c, 0x3c020001, 0x8c425d74, 0x3c04c00c,
-0x34842000, 0x3c030001, 0x8c635d98, 0x2102b,
-0x21023, 0x441024, 0x10600003, 0x518825,
-0x3c022000, 0x2228825, 0x3c020001, 0x451021,
-0x8c427e44, 0x10400003, 0x3c020020, 0x800535d,
-0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
-0x121140, 0x3c010001, 0x220821, 0x8c227e4c,
-0x10400003, 0x3c020080, 0x8005368, 0x2228825,
-0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001,
-0x8c425d60, 0x10400002, 0x3c020800, 0x2228825,
-0x3c020001, 0x8c425d64, 0x10400002, 0x3c020400,
-0x2228825, 0x3c020001, 0x8c425d68, 0x10400006,
-0x3c020100, 0x800537b, 0x2228825, 0x3c027fff,
-0x3442ffff, 0x628824, 0x121140, 0x3c010001,
-0x220821, 0xac317e30, 0x2201021, 0x8fbf0024,
-0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
-0x27bd0028, 0x27bdffd8, 0xafb40020, 0x80a021,
-0xafbf0024, 0xafb3001c, 0xafb20018, 0xafb10014,
-0xafb00010, 0x8f900200, 0x3c030001, 0x8c635cc8,
-0x8f930220, 0x24020002, 0x10620063, 0x2c620003,
-0x10400005, 0x24020001, 0x1062000a, 0x141940,
-0x8005448, 0x0, 0x24020004, 0x1062005a,
-0x24020008, 0x10620059, 0x149140, 0x8005448,
-0x0, 0x3c040001, 0x832021, 0x8c847e3c,
-0x3c110001, 0x2238821, 0x8e317e34, 0x3c024000,
-0x821024, 0x1040003e, 0x3c020008, 0x2221024,
-0x10400020, 0x36100002, 0x3c020001, 0x431021,
-0x8c427e40, 0x10400005, 0x36100020, 0x36100100,
-0x3c020020, 0x80053bd, 0x2228825, 0x2402feff,
-0x2028024, 0x3c02ffdf, 0x3442ffff, 0x2228824,
-0x141140, 0x3c010001, 0x220821, 0x8c227e48,
-0x10400005, 0x3c020001, 0x2629825, 0x3c020080,
-0x80053dc, 0x2228825, 0x3c02fffe, 0x3442ffff,
-0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80053dc,
-0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe,
-0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff,
-0x2228824, 0x3c010001, 0x230821, 0xac207e40,
-0x3c010001, 0x230821, 0xac207e48, 0xc00486a,
-0x0, 0xaf900200, 0xaf930220, 0x8f820220,
-0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
-0x34420002, 0xaf820220, 0x80053f3, 0x141140,
-0x8f820200, 0x2403fffd, 0x431024, 0xc00486a,
-0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
-0x2228824, 0x141140, 0x3c010001, 0x220821,
-0x8005448, 0xac317e34, 0x149140, 0x3c040001,
-0x922021, 0x8c847e38, 0x3c110001, 0x2328821,
-0x8e317e30, 0x3c024000, 0x821024, 0x14400011,
-0x0, 0x3c020001, 0x8c425d98, 0x14400006,
-0x3c02bfff, 0x8f820200, 0x34420002, 0xc00486a,
-0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
-0x2228824, 0x3c010001, 0x320821, 0x8005448,
-0xac317e30, 0x3c020001, 0x8c425d98, 0x10400005,
-0x3c020020, 0x3c020001, 0x8c425d74, 0x1040002b,
-0x3c020020, 0x821024, 0x10400007, 0x36100020,
-0x24020100, 0x3c010001, 0x320821, 0xac227e44,
-0x8005428, 0x36100100, 0x3c010001, 0x320821,
-0xac207e44, 0x2402feff, 0x2028024, 0x3c020080,
-0x821024, 0x10400007, 0x141940, 0x3c020001,
-0x3c010001, 0x230821, 0xac227e4c, 0x8005439,
-0x2629825, 0x141140, 0x3c010001, 0x220821,
-0xac207e4c, 0x3c02fffe, 0x3442ffff, 0x2629824,
-0xc00486a, 0x0, 0xaf900200, 0xaf930220,
-0x8f820220, 0x2403fffb, 0x431024, 0xaf820220,
-0x8f820220, 0x34420002, 0xaf820220, 0x141140,
-0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024,
-0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
-0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 };
-static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = {
-0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f66776d, 0x61696e2e, 0x632c7620, 0x312e312e,
-0x322e3131, 0x20313939, 0x382f3034, 0x2f323720,
-0x32323a31, 0x333a3432, 0x20736875, 0x616e6720,
-0x45787020, 0x24000000, 0x7468655f, 0x4441574e,
-0x0, 0x53544143, 0x4b5f3120, 0x0,
-0x42616453, 0x6e64526e, 0x67000000, 0x3f456e71,
-0x45767400, 0x3f6e6f51, 0x64457650, 0x0,
-0x6576526e, 0x6746756c, 0x6c000000, 0x496c6c43,
-0x6f6e6652, 0x78000000, 0x53656e64, 0x436b5375,
-0x6d000000, 0x52656376, 0x566c616e, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f74696d, 0x65722e63, 0x2c762031, 0x2e312e32,
-0x2e382031, 0x3939382f, 0x30372f33, 0x31203137,
-0x3a35383a, 0x34352073, 0x6875616e, 0x67204578,
-0x70202400, 0x542d446d, 0x61526431, 0x0,
-0x542d446d, 0x61424200, 0x542d446d, 0x61320000,
-0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51,
-0x64527845, 0x0, 0x656e714d, 0x45765046,
-0x61696c00, 0x656e714d, 0x45764661, 0x696c0000,
-0x6661696c, 0x456e454d, 0x0, 0x3f456e71,
-0x45767400, 0x3f6e6f51, 0x64457650, 0x0,
-0x6576526e, 0x6746756c, 0x6c000000, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f636f6d, 0x6d616e64, 0x2e632c76, 0x20312e31,
-0x2e322e31, 0x30203139, 0x39382f31, 0x312f3138,
-0x2031373a, 0x31313a31, 0x38207368, 0x75616e67,
-0x20457870, 0x20240000, 0x3f4d626f, 0x78457674,
-0x0, 0x4e4f636f, 0x6d616e64, 0x0,
-0x68737465, 0x5f455252, 0x0, 0x412d4572,
-0x72427563, 0x0, 0x4552524f, 0x522d4164,
-0x64000000, 0x656e714d, 0x45765046, 0x61696c00,
-0x656e714d, 0x45764661, 0x696c0000, 0x6661696c,
-0x456e454d, 0x0, 0x442d4572, 0x724c6173,
-0x74000000, 0x442d4572, 0x72320000, 0x6d437374,
-0x4d644552, 0x52000000, 0x70726f6d, 0x4d644552,
-0x52000000, 0x46696c74, 0x4d644552, 0x52000000,
-0x636d645f, 0x45525200, 0x3f456e71, 0x45767400,
-0x3f6e6f51, 0x64457650, 0x0, 0x6576526e,
-0x6746756c, 0x6c000000, 0x0, 0x6ea0,
-0x7fbc, 0x6e38, 0x8734, 0x82b0,
-0x8780, 0x8780, 0x6f54, 0x7694,
-0x7f0c, 0x80a8, 0x8074, 0x8780,
-0x7e70, 0x80cc, 0x6e64, 0x81cc,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f646d61, 0x2e632c76, 0x20312e31, 0x2e322e33,
-0x20313939, 0x382f3034, 0x2f323720, 0x32323a31,
-0x333a3431, 0x20736875, 0x616e6720, 0x45787020,
-0x24000000, 0x646d6172, 0x6441544e, 0x0,
-0x646d6177, 0x7241544e, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f747261, 0x63652e63, 0x2c762031, 0x2e312e32,
-0x2e322031, 0x3939382f, 0x30342f32, 0x37203232,
-0x3a31333a, 0x35302073, 0x6875616e, 0x67204578,
-0x70202400, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f646174, 0x612e632c, 0x7620312e, 0x312e322e,
-0x32203139, 0x39382f30, 0x342f3237, 0x2032323a,
-0x31333a34, 0x30207368, 0x75616e67, 0x20457870,
-0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20,
-0x23312046, 0x72692041, 0x70722037, 0x2031373a,
-0x35353a34, 0x38205044, 0x54203230, 0x30300000,
-0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a,
-0x2031373a, 0x35353a34, 0x38000000, 0x46575f43,
-0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263,
-0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48,
-0x4f53543a, 0x20636f6d, 0x70757465, 0x0,
-0x46575f43, 0x4f4d5049, 0x4c455f44, 0x4f4d4149,
-0x4e3a2065, 0x6e672e61, 0x6374656f, 0x6e2e636f,
-0x6d000000, 0x46575f43, 0x4f4d5049, 0x4c45523a,
-0x20676363, 0x20766572, 0x73696f6e, 0x20322e37,
-0x2e320000, 0x0, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f6d656d, 0x2e632c76, 0x20312e31, 0x2e322e32,
-0x20313939, 0x382f3034, 0x2f323720, 0x32323a31,
-0x333a3434, 0x20736875, 0x616e6720, 0x45787020,
-0x24000000, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f73656e, 0x642e632c, 0x7620312e, 0x312e322e,
-0x31312031, 0x3939382f, 0x31322f32, 0x32203137,
-0x3a31373a, 0x35352073, 0x6875616e, 0x67204578,
-0x70202400, 0x736e6464, 0x654e6f51, 0x20000000,
-0x6e6f454e, 0x515f5458, 0x0, 0x736e6464,
-0x744e6f51, 0x20000000, 0x3f6e6f51, 0x64547845,
-0x0, 0x756e6b72, 0x64747970, 0x65000000,
-0x0, 0xaccc, 0xaccc, 0xad9c,
-0xaab0, 0xaab0, 0xad9c, 0xad9c,
-0xad9c, 0xad9c, 0xad9c, 0xad9c,
-0xad9c, 0xad9c, 0xad9c, 0xad9c,
-0xad9c, 0xad9c, 0xad9c, 0xad7c,
-0x0, 0xbca8, 0xbca8, 0xbd70,
-0xae4c, 0xb058, 0xbd70, 0xbd70,
-0xbd70, 0xbd70, 0xbd70, 0xbd70,
-0xbd70, 0xbd70, 0xbd70, 0xbd70,
-0xbd70, 0xbd70, 0xbd70, 0xbd54,
-0xb040, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f726563, 0x762e632c, 0x7620312e, 0x312e322e,
-0x31392031, 0x3939382f, 0x30372f32, 0x34203231,
-0x3a33303a, 0x30352073, 0x6875616e, 0x67204578,
-0x70202400, 0x706b5278, 0x45525200, 0x66726d32,
-0x4c617267, 0x65000000, 0x72784e6f, 0x52784264,
-0x0, 0x72785144, 0x6d614446, 0x0,
-0x72785144, 0x6d614246, 0x0, 0x3f6e6f51,
-0x64527845, 0x0, 0x706b5278, 0x45525273,
-0x0, 0x66726d32, 0x4c726753, 0x0,
-0x72784e6f, 0x42645300, 0x3f724264, 0x446d6146,
-0x0, 0x3f724a42, 0x64446d46, 0x0,
-0x0, 0xf678, 0xf678, 0xf678,
-0xf678, 0xf678, 0xf678, 0xf678,
-0xf678, 0xf678, 0xf678, 0xf678,
-0xf678, 0xf678, 0xf678, 0xf678,
-0xf670, 0xf670, 0xf670, 0x572d444d,
-0x41456e46, 0x0, 0x0, 0xfdc0,
-0x1015c, 0xfddc, 0x1015c, 0x1015c,
-0x1015c, 0x1015c, 0x1015c, 0x1015c,
-0xf704, 0x1015c, 0x1015c, 0x1015c,
-0x1015c, 0x1015c, 0x10154, 0x10154,
-0x10154, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f6d6163, 0x2e632c76, 0x20312e31, 0x2e322e31,
-0x32203139, 0x39382f30, 0x342f3237, 0x2032323a,
-0x31333a34, 0x32207368, 0x75616e67, 0x20457870,
-0x20240000, 0x6d616374, 0x7841544e, 0x0,
-0x4e745379, 0x6e264c6b, 0x0, 0x72656d61,
-0x73737274, 0x0, 0x6c696e6b, 0x444f574e,
-0x0, 0x656e714d, 0x45765046, 0x61696c00,
-0x656e714d, 0x45764661, 0x696c0000, 0x6661696c,
-0x456e454d, 0x0, 0x6c696e6b, 0x55500000,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f636b73, 0x756d2e63, 0x2c762031, 0x2e312e32,
-0x2e322031, 0x3939382f, 0x30342f32, 0x37203232,
-0x3a31333a, 0x33392073, 0x6875616e, 0x67204578,
-0x70202400, 0x50726f62, 0x65506879, 0x0,
-0x6c6e6b41, 0x53535254, 0x0, 0x11b2c,
-0x11bc4, 0x11bf8, 0x11c2c, 0x11c58,
-0x11c6c, 0x11ca8, 0x1207c, 0x11de4,
-0x11e24, 0x11e50, 0x11e90, 0x11ec0,
-0x11efc, 0x11f30, 0x1207c, 0x122c0,
-0x122d8, 0x12300, 0x12320, 0x12348,
-0x12478, 0x124a0, 0x124f4, 0x1251c,
-0x0, 0x1278c, 0x1285c, 0x12934,
-0x12a04, 0x12a60, 0x12b3c, 0x12b64,
-0x12c40, 0x12c68, 0x12e10, 0x12e38,
-0x12fe0, 0x131d8, 0x1346c, 0x13380,
-0x1346c, 0x13498, 0x13008, 0x131b0,
-0x0, 0x13b84, 0x13bc8, 0x13c60,
-0x13cac, 0x13d1c, 0x13db4, 0x13de8,
-0x13e70, 0x13f08, 0x13fd8, 0x14018,
-0x1409c, 0x140c0, 0x141f4, 0x646f4261,
-0x73655067, 0x0, 0x0, 0x0,
-0x0, 0x73746d61, 0x634c4e4b, 0x0,
-0x0, 0x14c38, 0x14c38, 0x14b80,
-0x14bc4, 0x14c38, 0x14c38, 0x0,
-0x0, 0x0 };
-static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __devinitdata = {
-0x416c7465,
-0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465,
-0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242,
-0x0, 0x0, 0x0, 0x135418,
-0x13e7fc, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x60cf00,
-0x60, 0xcf000000, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x3, 0x0,
-0x1, 0x0, 0x0, 0x0,
-0x1, 0x0, 0x1, 0x0,
-0x0, 0x0, 0x0, 0x1,
-0x1, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x1000000, 0x21000000,
-0x12000140, 0x0, 0x0, 0x20000000,
-0x120000a0, 0x0, 0x12000060, 0x12000180,
-0x120001e0, 0x0, 0x0, 0x0,
-0x1, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x2,
-0x0, 0x0, 0x30001, 0x1,
-0x30201, 0x0, 0x0, 0x0 };
-#endif
-/* Generated by genfw.c */
-#define tigon2FwReleaseMajor 0xc
-#define tigon2FwReleaseMinor 0x4
-#define tigon2FwReleaseFix 0xb
-#define tigon2FwStartAddr 0x00004000
-#define tigon2FwTextAddr 0x00004000
-#define tigon2FwTextLen 0x11bc0
-#define tigon2FwRodataAddr 0x00015bc0
-#define tigon2FwRodataLen 0x10d0
-#define tigon2FwDataAddr 0x00016cc0
-#define tigon2FwDataLen 0x1c0
-#define tigon2FwSbssAddr 0x00016e80
-#define tigon2FwSbssLen 0xcc
-#define tigon2FwBssAddr 0x00016f50
-#define tigon2FwBssLen 0x20c0
-static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = {
-0x0,
-0x10000003, 0x0, 0xd, 0xd,
-0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000,
-0x26104000, 0xc0010c0, 0x0, 0xd,
-0x3c1d0001, 0x8fbd6d24, 0x3a0f021, 0x3c100000,
-0x26104000, 0xc0017e0, 0x0, 0xd,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x2000008,
-0x0, 0x800172f, 0x3c0a0001, 0x800172f,
-0x3c0a0002, 0x800172f, 0x0, 0x8002cac,
-0x0, 0x8002c4f, 0x0, 0x800172f,
-0x3c0a0004, 0x800328a, 0x0, 0x8001a52,
-0x0, 0x800394d, 0x0, 0x80038f4,
-0x0, 0x800172f, 0x3c0a0006, 0x80039bb,
-0x3c0a0007, 0x800172f, 0x3c0a0008, 0x800172f,
-0x3c0a0009, 0x8003a13, 0x0, 0x8002ea6,
-0x0, 0x800172f, 0x3c0a000b, 0x800172f,
-0x3c0a000c, 0x800172f, 0x3c0a000d, 0x80028fb,
-0x0, 0x8002890, 0x0, 0x800172f,
-0x3c0a000e, 0x800208c, 0x0, 0x8001964,
-0x0, 0x8001a04, 0x0, 0x8003ca6,
-0x0, 0x8003c94, 0x0, 0x800172f,
-0x0, 0x800191a, 0x0, 0x800172f,
-0x0, 0x800172f, 0x3c0a0013, 0x800172f,
-0x3c0a0014, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x27bdffe0,
-0x3c1cc000, 0xafbf001c, 0xafb00018, 0x8f820140,
-0x24030003, 0xaf8300ec, 0x34420004, 0xc002b20,
-0xaf820140, 0x3c0100c0, 0xc001763, 0xac203ffc,
-0x401821, 0x3c020010, 0x3c010001, 0xac236e9c,
-0x10620011, 0x43102b, 0x14400002, 0x3c020020,
-0x3c020008, 0x1062000c, 0x24050100, 0x3c060001,
-0x8cc66e9c, 0x3c040001, 0x24845c74, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020020,
-0x3c010001, 0xac226e9c, 0x24020008, 0x3c010001,
-0xac226eb4, 0x2402001f, 0x3c010001, 0xac226ec4,
-0x24020016, 0x3c010001, 0xac226e98, 0x3c05fffe,
-0x34a56f08, 0x3c020001, 0x8c426e9c, 0x3c030002,
-0x24639010, 0x3c040001, 0x8c846cc4, 0x431023,
-0x14800002, 0x458021, 0x2610fa38, 0x2402f000,
-0x2028024, 0xc001785, 0x2002021, 0x2022823,
-0x3c040020, 0x821823, 0x651823, 0x247bb000,
-0x3c03fffe, 0x3463bf08, 0x363b821, 0x3c0600bf,
-0x34c6f000, 0x3c070001, 0x8ce76cc0, 0x3c0300bf,
-0x3463e000, 0x852023, 0x3c010001, 0xac246ea8,
-0x822023, 0x3c010001, 0xac256e90, 0x52842,
-0x3c010001, 0xac226e84, 0x27620ffc, 0x3c010001,
-0xac226d20, 0x27621ffc, 0xdb3023, 0x7b1823,
-0x3c010001, 0xac246e88, 0x3c010001, 0xac256eac,
-0x3c010001, 0xac226d24, 0xaf860150, 0x10e00011,
-0xaf830250, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021,
-0xc001749, 0x0, 0x3c020001, 0x8c426cd0,
-0x3c030001, 0x8c636cd4, 0x2442fe00, 0x24630200,
-0x3c010001, 0xac226cd0, 0x3c010001, 0x10000004,
-0xac236cd4, 0x3c1d0001, 0x8fbd6d20, 0x3a0f021,
-0x3c020001, 0x8c426cc4, 0x1040000d, 0x26fafa38,
-0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
-0x3c1a0001, 0x8f5a6cd4, 0x2442fa38, 0x246305c8,
-0x3c010001, 0xac226cd0, 0x3c010001, 0xac236cd4,
-0x3c020001, 0x8c426cc8, 0x14400003, 0x0,
-0x3c010001, 0xac206cd0, 0xc001151, 0x0,
-0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
-0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
-0x27bdff98, 0xafb00048, 0x3c100001, 0x8e1066b8,
-0xafb20050, 0x3c120000, 0x26524100, 0xafbf0060,
-0xafbe005c, 0xafb50058, 0xafb30054, 0xafb1004c,
-0xafa20034, 0xafa30030, 0xafa00010, 0xafa00014,
-0x8f860040, 0x3c040001, 0x24845c80, 0x24050200,
-0x3c010001, 0xac326e80, 0xc002b3b, 0x2003821,
-0x8f830040, 0x3c02f000, 0x621824, 0x3c026000,
-0x1062000b, 0xa3a0003f, 0x240e0001, 0x3c040001,
-0x24845c88, 0xa3ae003f, 0xafa00010, 0xafa00014,
-0x8f860040, 0x24050300, 0xc002b3b, 0x2003821,
-0x8f820240, 0x3c030001, 0x431025, 0xaf820240,
-0xaf800048, 0x8f820048, 0x14400005, 0x0,
-0xaf800048, 0x8f820048, 0x10400004, 0x0,
-0xaf800048, 0x10000003, 0x2e02021, 0xaf80004c,
-0x2e02021, 0x3c050001, 0xc002ba8, 0x34a540f8,
-0x3402021, 0xc002ba8, 0x240505c8, 0x3c020001,
-0x8c426ea8, 0x3c0d0001, 0x8dad6e88, 0x3c030001,
-0x8c636e84, 0x3c080001, 0x8d086e90, 0x3c090001,
-0x8d296eac, 0x3c0a0001, 0x8d4a6eb4, 0x3c0b0001,
-0x8d6b6ec4, 0x3c0c0001, 0x8d8c6e98, 0x3c040001,
-0x24845c94, 0x24050400, 0xaf42013c, 0x8f42013c,
-0x24060001, 0x24070001, 0xaf400000, 0xaf4d0138,
-0xaf430144, 0xaf480148, 0xaf49014c, 0xaf4a0150,
-0xaf4b0154, 0xaf4c0158, 0x2442ff80, 0xaf420140,
-0x24020001, 0xafa20010, 0xc002b3b, 0xafa00014,
-0x8f420138, 0xafa20010, 0x8f42013c, 0xafa20014,
-0x8f460144, 0x8f470148, 0x3c040001, 0x24845ca0,
-0xc002b3b, 0x24050500, 0xafb70010, 0xafba0014,
-0x8f46014c, 0x8f470150, 0x3c040001, 0x24845cac,
-0xc002b3b, 0x24050600, 0x3c020001, 0x8c426e9c,
-0x3603821, 0x3c060002, 0x24c69010, 0x2448ffff,
-0x1061824, 0xe81024, 0x43102b, 0x10400006,
-0x24050900, 0x3c040001, 0x24845cb8, 0xafa80010,
-0xc002b3b, 0xafa00014, 0x8f82000c, 0xafa20010,
-0x8f82003c, 0xafa20014, 0x8f860000, 0x8f870004,
-0x3c040001, 0x24845cc4, 0xc002b3b, 0x24051000,
-0x8c020220, 0x8c030224, 0x8c060218, 0x8c07021c,
-0x3c040001, 0x24845ccc, 0x24051100, 0xafa20010,
-0xc002b3b, 0xafa30014, 0xaf800054, 0xaf80011c,
-0x8c020218, 0x30420002, 0x10400009, 0x0,
-0x8c020220, 0x3c030002, 0x34630004, 0x431025,
-0xaf42000c, 0x8c02021c, 0x10000008, 0x34420004,
-0x8c020220, 0x3c030002, 0x34630006, 0x431025,
-0xaf42000c, 0x8c02021c, 0x34420006, 0xaf420014,
-0x8c020218, 0x30420010, 0x1040000a, 0x0,
-0x8c02021c, 0x34420004, 0xaf420010, 0x8c020220,
-0x3c03000a, 0x34630004, 0x431025, 0x10000009,
-0xaf420008, 0x8c020220, 0x3c03000a, 0x34630006,
-0x431025, 0xaf420008, 0x8c02021c, 0x34420006,
-0xaf420010, 0x24020001, 0xaf8200a0, 0xaf8200b0,
-0x8f830054, 0x8f820054, 0xaf8000d0, 0xaf8000c0,
-0x10000002, 0x24630064, 0x8f820054, 0x621023,
-0x2c420065, 0x1440fffc, 0x0, 0x8c040208,
-0x8c05020c, 0x26e20028, 0xaee20020, 0x24020490,
-0xaee20010, 0xaee40008, 0xaee5000c, 0x26e40008,
-0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094,
-0x8c820018, 0xaf8200b4, 0x9482000a, 0xaf82009c,
-0x8f420014, 0xaf8200b0, 0x8f8200b0, 0x30420004,
-0x1440fffd, 0x0, 0x8f8200b0, 0x3c03ef00,
-0x431024, 0x10400021, 0x0, 0x8f8200b4,
-0xafa20010, 0x8f820090, 0x8f830094, 0x3c040001,
-0x24845cd4, 0xafa30014, 0x8f8600b0, 0x8f87009c,
-0x3c050001, 0xc002b3b, 0x34a5200d, 0x3c040001,
-0x24845ce0, 0x240203c0, 0xafa20010, 0xafa00014,
-0x8f860144, 0x3c070001, 0x24e75ce8, 0xc002b3b,
-0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
-0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
-0x3c030001, 0x431025, 0xaf820140, 0x96e20472,
-0x96e60452, 0x96e70462, 0xafa20010, 0x96e20482,
-0x3c040001, 0x24845d14, 0x24051200, 0xc002b3b,
-0xafa20014, 0x96f00452, 0x32020001, 0x10400002,
-0xb021, 0x24160001, 0x32020002, 0x54400001,
-0x36d60002, 0x32020008, 0x54400001, 0x36d60004,
-0x32020010, 0x54400001, 0x36d60008, 0x32020020,
-0x54400001, 0x36d60010, 0x32020040, 0x54400001,
-0x36d60020, 0x32020080, 0x54400001, 0x36d60040,
-0x96e60482, 0x30c20200, 0x54400001, 0x36d64000,
-0x96e30472, 0x30620200, 0x10400003, 0x30620100,
-0x10000003, 0x36d62000, 0x54400001, 0x36d61000,
-0x96f00462, 0x32c24000, 0x14400004, 0x3207009b,
-0x30c2009b, 0x14e20007, 0x240e0001, 0x32c22000,
-0x1440000d, 0x32020001, 0x3062009b, 0x10e20009,
-0x240e0001, 0x3c040001, 0x24845d20, 0x24051300,
-0x2003821, 0xa3ae003f, 0xafa30010, 0xc002b3b,
-0xafa00014, 0x32020001, 0x54400001, 0x36d60080,
-0x32020002, 0x54400001, 0x36d60100, 0x32020008,
-0x54400001, 0x36d60200, 0x32020010, 0x54400001,
-0x36d60400, 0x32020080, 0x54400001, 0x36d60800,
-0x8c020218, 0x30420200, 0x10400002, 0x3c020008,
-0x2c2b025, 0x8c020218, 0x30420800, 0x10400002,
-0x3c020080, 0x2c2b025, 0x8c020218, 0x30420400,
-0x10400002, 0x3c020100, 0x2c2b025, 0x8c020218,
-0x30420100, 0x10400002, 0x3c020200, 0x2c2b025,
-0x8c020218, 0x30420080, 0x10400002, 0x3c020400,
-0x2c2b025, 0x8c020218, 0x30422000, 0x10400002,
-0x3c020010, 0x2c2b025, 0x8c020218, 0x30424000,
-0x10400002, 0x3c020020, 0x2c2b025, 0x8c020218,
-0x30421000, 0x10400002, 0x3c020040, 0x2c2b025,
-0x8ee20498, 0x8ee3049c, 0xaf420160, 0xaf430164,
-0x8ee204a0, 0x8ee304a4, 0xaf420168, 0xaf43016c,
-0x8ee204a8, 0x8ee304ac, 0xaf420170, 0xaf430174,
-0x8ee20428, 0x8ee3042c, 0xaf420178, 0xaf43017c,
-0x8ee20448, 0x8ee3044c, 0xaf420180, 0xaf430184,
-0x8ee20458, 0x8ee3045c, 0xaf420188, 0xaf43018c,
-0x8ee20468, 0x8ee3046c, 0xaf420190, 0xaf430194,
-0x8ee20478, 0x8ee3047c, 0xaf420198, 0xaf43019c,
-0x8ee20488, 0x8ee3048c, 0xaf4201a0, 0xaf4301a4,
-0x8ee204b0, 0x8ee304b4, 0x24040080, 0xaf4201a8,
-0xaf4301ac, 0xc002ba8, 0x24050080, 0x8c02025c,
-0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200,
-0x24060008, 0xc002bbf, 0xaf4201f8, 0x3c043b9a,
-0x3484ca00, 0x3821, 0x24020006, 0x24030002,
-0xaf4201f4, 0x240203e8, 0xaf430204, 0xaf430200,
-0xaf4401fc, 0xaf420294, 0x24020001, 0xaf430290,
-0xaf42029c, 0x3c030001, 0x671821, 0x90636cd8,
-0x3471021, 0x24e70001, 0xa043022c, 0x2ce2000f,
-0x1440fff8, 0x3471821, 0x24e70001, 0x3c080001,
-0x350840f8, 0x8f820040, 0x3c040001, 0x24845d2c,
-0x24051400, 0x21702, 0x24420030, 0xa062022c,
-0x3471021, 0xa040022c, 0x8c070218, 0x2c03021,
-0x240205c8, 0xafa20010, 0xc002b3b, 0xafa80014,
-0x3c040001, 0x24845d38, 0x3c050000, 0x24a55c80,
-0x24060010, 0x27b10030, 0x2203821, 0x27b30034,
-0xc0017a3, 0xafb30010, 0x3c030001, 0x8c636cc8,
-0x1060000a, 0x408021, 0x8fa30030, 0x2405ff00,
-0x8fa20034, 0x246400ff, 0x852024, 0x831823,
-0x431023, 0xafa20034, 0xafa40030, 0x3c040001,
-0x24845d44, 0x3c050000, 0x24a54100, 0x24060108,
-0x2203821, 0xc0017a3, 0xafb30010, 0x409021,
-0x32c20003, 0x3c010001, 0xac326e80, 0x10400045,
-0x2203821, 0x8f820050, 0x3c030010, 0x431024,
-0x10400016, 0x0, 0x8c020218, 0x30420040,
-0x1040000f, 0x24020001, 0x8f820050, 0x8c030218,
-0x240e0001, 0x3c040001, 0x24845d50, 0xa3ae003f,
-0xafa20010, 0xafa30014, 0x8f870040, 0x24051500,
-0xc002b3b, 0x2c03021, 0x10000004, 0x0,
-0x3c010001, 0x370821, 0xa02240f4, 0x3c040001,
-0x24845d5c, 0x3c050001, 0x24a55b40, 0x3c060001,
-0x24c65bac, 0xc53023, 0x8f420010, 0x27b30030,
-0x2603821, 0x27b10034, 0x34420a00, 0xaf420010,
-0xc0017a3, 0xafb10010, 0x3c040001, 0x24845d70,
-0x3c050001, 0x24a5b714, 0x3c060001, 0x24c6ba90,
-0xc53023, 0x2603821, 0xaf420108, 0xc0017a3,
-0xafb10010, 0x3c040001, 0x24845d8c, 0x3c050001,
-0x24a5be58, 0x3c060001, 0x24c6c900, 0xc53023,
-0x2603821, 0x3c010001, 0xac226ef4, 0xc0017a3,
-0xafb10010, 0x3c040001, 0x24845da4, 0x10000024,
-0x24051600, 0x3c040001, 0x24845dac, 0x3c050001,
-0x24a5a10c, 0x3c060001, 0x24c6a238, 0xc53023,
-0xc0017a3, 0xafb30010, 0x3c040001, 0x24845dbc,
-0x3c050001, 0x24a5b2b0, 0x3c060001, 0x24c6b70c,
-0xc53023, 0x2203821, 0xaf420108, 0xc0017a3,
-0xafb30010, 0x3c040001, 0x24845dd0, 0x3c050001,
-0x24a5ba98, 0x3c060001, 0x24c6be50, 0xc53023,
-0x2203821, 0x3c010001, 0xac226ef4, 0xc0017a3,
-0xafb30010, 0x3c040001, 0x24845de4, 0x24051650,
-0x2c03021, 0x3821, 0x3c010001, 0xac226ef8,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x32c20020,
-0x10400021, 0x27a70030, 0x3c040001, 0x24845df0,
-0x3c050001, 0x24a5b13c, 0x3c060001, 0x24c6b2a8,
-0xc53023, 0x24022000, 0xaf42001c, 0x27a20034,
-0xc0017a3, 0xafa20010, 0x21900, 0x31982,
-0x3c040800, 0x641825, 0xae430028, 0x24030010,
-0xaf43003c, 0x96e30450, 0xaf430040, 0x8f430040,
-0x3c040001, 0x24845e04, 0xafa00014, 0xafa30010,
-0x8f47001c, 0x24051660, 0x3c010001, 0xac226ef0,
-0x10000025, 0x32c60020, 0x8ee20448, 0x8ee3044c,
-0xaf43001c, 0x8f42001c, 0x2442e000, 0x2c422001,
-0x1440000a, 0x240e0001, 0x3c040001, 0x24845e10,
-0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f46001c,
-0x24051700, 0xc002b3b, 0x3821, 0x3c020000,
-0x24425cbc, 0x21100, 0x21182, 0x3c030800,
-0x431025, 0xae420028, 0x24020008, 0xaf42003c,
-0x96e20450, 0xaf420040, 0x8f420040, 0x3c040001,
-0x24845e1c, 0xafa00014, 0xafa20010, 0x8f47001c,
-0x24051800, 0x32c60020, 0xc002b3b, 0x0,
-0x3c050fff, 0x3c030001, 0x8c636ef4, 0x34a5ffff,
-0x2403021, 0x3c020001, 0x8c426ef8, 0x3c040800,
-0x651824, 0x31882, 0x641825, 0x451024,
-0x21082, 0x441025, 0xacc20080, 0x32c20180,
-0x10400056, 0xacc30020, 0x8f82005c, 0x3c030080,
-0x431024, 0x1040000d, 0x0, 0x8f820050,
-0xafa20010, 0x8f82005c, 0x240e0001, 0x3c040001,
-0x24845e28, 0xa3ae003f, 0xafa20014, 0x8f870040,
-0x24051900, 0xc002b3b, 0x2c03021, 0x8f820050,
-0x3c030010, 0x431024, 0x10400016, 0x0,
-0x8c020218, 0x30420040, 0x1040000f, 0x24020001,
-0x8f820050, 0x8c030218, 0x240e0001, 0x3c040001,
-0x24845d50, 0xa3ae003f, 0xafa20010, 0xafa30014,
-0x8f870040, 0x24052000, 0xc002b3b, 0x2c03021,
-0x10000004, 0x0, 0x3c010001, 0x370821,
-0xa02240f4, 0x3c040001, 0x24845e34, 0x3c050001,
-0x24a55ac0, 0x3c060001, 0x24c65b38, 0xc53023,
-0x8f420008, 0x27b30030, 0x2603821, 0x27b10034,
-0x34420e00, 0xaf420008, 0xc0017a3, 0xafb10010,
-0x3c040001, 0x24845e4c, 0x3c050001, 0x24a5d8b4,
-0x3c060001, 0x24c6e3c8, 0xc53023, 0x2603821,
-0xaf42010c, 0xc0017a3, 0xafb10010, 0x3c040001,
-0x24845e64, 0x3c050001, 0x24a5e9ac, 0x3c060001,
-0x24c6f0f0, 0xc53023, 0x2603821, 0x3c010001,
-0xac226f04, 0xc0017a3, 0xafb10010, 0x3c040001,
-0x24845e7c, 0x10000027, 0x24052100, 0x3c040001,
-0x24845e84, 0x3c050001, 0x24a59fc8, 0x3c060001,
-0x24c6a104, 0xc53023, 0x27b10030, 0x2203821,
-0x27b30034, 0xc0017a3, 0xafb30010, 0x3c040001,
-0x24845e94, 0x3c050001, 0x24a5cad4, 0x3c060001,
-0x24c6d8ac, 0xc53023, 0x2203821, 0xaf42010c,
-0xc0017a3, 0xafb30010, 0x3c040001, 0x24845ea4,
-0x3c050001, 0x24a5e84c, 0x3c060001, 0x24c6e9a4,
-0xc53023, 0x2203821, 0x3c010001, 0xac226f04,
-0xc0017a3, 0xafb30010, 0x3c040001, 0x24845eb8,
-0x24052150, 0x2c03021, 0x3821, 0x3c010001,
-0xac226f10, 0xafa00010, 0xc002b3b, 0xafa00014,
-0x3c110fff, 0x3c030001, 0x8c636f04, 0x3631ffff,
-0x2409821, 0x3c020001, 0x8c426f10, 0x3c0e0800,
-0x711824, 0x31882, 0x6e1825, 0x511024,
-0x21082, 0x4e1025, 0xae630038, 0xae620078,
-0x8c020218, 0x30420040, 0x14400004, 0x24020001,
-0x3c010001, 0x370821, 0xa02240f4, 0x3c040001,
-0x24845ec4, 0x3c050001, 0x24a5e3d0, 0x3c060001,
-0x24c6e52c, 0xc53023, 0x27be0030, 0x3c03821,
-0x27b50034, 0xc0017a3, 0xafb50010, 0x3c010001,
-0xac226efc, 0x511024, 0x21082, 0x3c0e0800,
-0x4e1025, 0xae620050, 0x32c22000, 0x10400006,
-0x3c03821, 0x3c020000, 0x24425cbc, 0x2221024,
-0x1000000f, 0x21082, 0x3c040001, 0x24845ed8,
-0x3c050001, 0x24a5e534, 0x3c060001, 0x24c6e6e4,
-0xc53023, 0xc0017a3, 0xafb50010, 0x3c010001,
-0xac226f14, 0x511024, 0x21082, 0x3c0e0800,
-0x4e1025, 0xae620048, 0x32c24000, 0x10400005,
-0x27a70030, 0x3c020000, 0x24425cbc, 0x1000000e,
-0x21100, 0x3c040001, 0x24845ef0, 0x3c050001,
-0x24a5e6ec, 0x3c060001, 0x24c6e844, 0xc53023,
-0x27a20034, 0xc0017a3, 0xafa20010, 0x3c010001,
-0xac226f08, 0x21100, 0x21182, 0x3c030800,
-0x431025, 0xae420060, 0x3c040001, 0x24845f08,
-0x3c050001, 0x24a58230, 0x3c060001, 0x24c68650,
-0xc53023, 0x27b10030, 0x2203821, 0x27b30034,
-0xc0017a3, 0xafb30010, 0x3c0e0fff, 0x35ceffff,
-0x3c040001, 0x24845f14, 0x3c050000, 0x24a56468,
-0x3c060000, 0x24c66588, 0xc53023, 0x2203821,
-0x240f021, 0x3c010001, 0xac226edc, 0x4e1024,
-0x21082, 0x3c150800, 0x551025, 0xafae0044,
-0xafc200b8, 0xc0017a3, 0xafb30010, 0x3c040001,
-0x24845f20, 0x3c050000, 0x24a56590, 0x3c060000,
-0x24c66808, 0x8fae0044, 0xc53023, 0x2203821,
-0x3c010001, 0xac226ed0, 0x4e1024, 0x21082,
-0x551025, 0xafc200e8, 0xc0017a3, 0xafb30010,
-0x3c040001, 0x24845f38, 0x3c050000, 0x24a56810,
-0x3c060000, 0x24c66940, 0x8fae0044, 0xc53023,
-0x2203821, 0x3c010001, 0xac226ec8, 0x4e1024,
-0x21082, 0x551025, 0xafc200c0, 0xc0017a3,
-0xafb30010, 0x3c040001, 0x24845f50, 0x3c050001,
-0x24a5fad0, 0x3c060001, 0x24c6fba8, 0x8fae0044,
-0xc53023, 0x2203821, 0x3c010001, 0xac226ed4,
-0x4e1024, 0x21082, 0x551025, 0xafc200c8,
-0xc0017a3, 0xafb30010, 0x3c040001, 0x24845f5c,
-0x3c050001, 0x24a5c93c, 0x3c060001, 0x24c6ca20,
-0xc53023, 0x2203821, 0xaf420110, 0xc0017a3,
-0xafb30010, 0x3c040001, 0x24845f6c, 0x3c050001,
-0x24a5c910, 0x3c060001, 0x24c6c934, 0xc53023,
-0x2203821, 0xaf420124, 0xc0017a3, 0xafb30010,
-0x3c040001, 0x24845f7c, 0x3c050001, 0x24a55a80,
-0x3c060001, 0x24c65aac, 0xc53023, 0x2203821,
-0xaf420120, 0xaf420114, 0xc0017a3, 0xafb30010,
-0x3c040001, 0x24845f88, 0x3c050001, 0x24a5f298,
-0x3c060001, 0x24c6f6b4, 0xc53023, 0x2203821,
-0xaf420118, 0xc0017a3, 0xafb30010, 0x8fae0044,
-0x3c010001, 0xac226f18, 0x4e1024, 0x21082,
-0x551025, 0xc003fc3, 0xafc200d0, 0xc003c40,
-0x0, 0xc0027a8, 0x0, 0xac000228,
-0xac00022c, 0x96e20450, 0x2442ffff, 0xaf420038,
-0x96e20460, 0xaf420080, 0x32c24000, 0x14400003,
-0x0, 0x96e20480, 0xaf420084, 0x96e70490,
-0x50e00001, 0x24070800, 0x24e2ffff, 0xaf420088,
-0xaf42007c, 0x24020800, 0x10e2000f, 0x32c24000,
-0x10400003, 0x24020400, 0x10e2000b, 0x0,
-0x240e0001, 0x3c040001, 0x24845f98, 0xa3ae003f,
-0x96e60490, 0x24052170, 0x2c03821, 0xafa00010,
-0xc002b3b, 0xafa00014, 0x8f430138, 0x8f440138,
-0x24020001, 0xa34205c2, 0xaf430094, 0xaf440098,
-0xafa00010, 0xafa00014, 0x8f460080, 0x8f470084,
-0x3c040001, 0x24845fa4, 0xc002b3b, 0x24052200,
-0xc0024a4, 0x3c110800, 0x3c1433d8, 0x3694cb58,
-0x3c020800, 0x34420080, 0x3c040001, 0x24845fb0,
-0x3c050000, 0x24a55d00, 0x3c060000, 0x24c65d1c,
-0xc53023, 0x27a70030, 0xaf820060, 0x2402ffff,
-0xaf820064, 0x27a20034, 0xc0017a3, 0xafa20010,
-0x3c010001, 0xac226eb8, 0x21100, 0x21182,
-0x511025, 0xc0018fc, 0xae420000, 0x8f820240,
-0x3c030001, 0x431025, 0xaf820240, 0x3c020000,
-0x24424034, 0xaf820244, 0xaf800240, 0x8f820060,
-0x511024, 0x14400005, 0x3c030800, 0x8f820060,
-0x431024, 0x1040fffd, 0x0, 0xc003c4d,
-0x8821, 0x3c020100, 0xafa20020, 0x8f530018,
-0x240200ff, 0x56620001, 0x26710001, 0x8c020228,
-0x1622000e, 0x1330c0, 0x8f42033c, 0x24420001,
-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
-0x24845c24, 0x3c050009, 0xafa00014, 0xafa20010,
-0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021,
-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
-0xc01821, 0x8f440178, 0x8f45017c, 0x1021,
-0x24070004, 0xafa70010, 0xafb10014, 0x8f48000c,
-0x24c604c0, 0x2e63021, 0xafa80018, 0x8f48010c,
-0x24070008, 0xa32821, 0xa3482b, 0x822021,
-0x100f809, 0x892021, 0x1440000b, 0x24070008,
-0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24845c2c, 0x3c050009, 0xafa20014, 0x8fa60020,
-0x1000001c, 0x34a50200, 0x8f440160, 0x8f450164,
-0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010,
-0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c,
-0x40f809, 0x24c6001c, 0x14400010, 0x0,
-0x8f420340, 0x24420001, 0xaf420340, 0x8f420340,
-0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24845c34, 0x3c050009, 0xafa20014, 0x8fa60020,
-0x34a50300, 0xc002b3b, 0x2603821, 0x8f4202e4,
-0x24420001, 0xaf4202e4, 0x8f4202e4, 0x93a2003f,
-0x10400069, 0x3c020700, 0x34423000, 0xafa20028,
-0x8f530018, 0x240200ff, 0x12620002, 0x8821,
-0x26710001, 0x8c020228, 0x1622000e, 0x1330c0,
-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
-0x8c020228, 0x3c040001, 0x24845c24, 0x3c050009,
-0xafa00014, 0xafa20010, 0x8fa60028, 0x1000003f,
-0x34a50100, 0xd71021, 0x8fa30028, 0x8fa4002c,
-0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
-0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
-0xafb10014, 0x8f48000c, 0x24c604c0, 0x2e63021,
-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
-0xa3482b, 0x822021, 0x100f809, 0x892021,
-0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24845c2c, 0x3c050009,
-0xafa20014, 0x8fa60028, 0x1000001c, 0x34a50200,
-0x8f440160, 0x8f450164, 0x8f43000c, 0xaf510018,
-0x8f860120, 0x24020010, 0xafa20010, 0xafb10014,
-0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x14400010, 0x0, 0x8f420340, 0x24420001,
-0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24845c34, 0x3c050009,
-0xafa20014, 0x8fa60028, 0x34a50300, 0xc002b3b,
-0x2603821, 0x8f4202f0, 0x24420001, 0xaf4202f0,
-0x8f4202f0, 0x3c040001, 0x24845fc0, 0xafa00010,
-0xafa00014, 0x8fa60028, 0x24052300, 0xc002b3b,
-0x3821, 0x10000004, 0x0, 0x8c020264,
-0x10400005, 0x0, 0x8f8200a0, 0x30420004,
-0x1440fffa, 0x0, 0x8f820044, 0x34420004,
-0xaf820044, 0x8f420308, 0x24420001, 0xaf420308,
-0x8f420308, 0x8f8200d8, 0x8f8300d4, 0x431023,
-0x2442ff80, 0xaf420090, 0x8f420090, 0x2842ff81,
-0x10400006, 0x24020001, 0x8f420090, 0x8f430144,
-0x431021, 0xaf420090, 0x24020001, 0xaf42008c,
-0x32c20008, 0x10400006, 0x0, 0x8f820214,
-0x3c038100, 0x3042ffff, 0x431025, 0xaf820214,
-0x3c030001, 0x8c636d94, 0x30620002, 0x10400009,
-0x30620001, 0x3c040001, 0x24845fcc, 0x3c050000,
-0x24a56d50, 0x3c060000, 0x24c671c8, 0x10000012,
-0xc53023, 0x10400009, 0x0, 0x3c040001,
-0x24845fdc, 0x3c050000, 0x24a571d0, 0x3c060000,
-0x24c67678, 0x10000008, 0xc53023, 0x3c040001,
-0x24845fec, 0x3c050000, 0x24a56948, 0x3c060000,
-0x24c66d48, 0xc53023, 0x27a70030, 0x27a20034,
-0xc0017a3, 0xafa20010, 0x3c010001, 0xac226ecc,
-0x3c020001, 0x8c426ecc, 0x3c030800, 0x21100,
-0x21182, 0x431025, 0xae420040, 0x8f8200a0,
-0xafa20010, 0x8f8200b0, 0xafa20014, 0x8f86005c,
-0x8f87011c, 0x3c040001, 0x24845ffc, 0x3c010001,
-0xac366ea4, 0x3c010001, 0xac206e94, 0x3c010001,
-0xac3c6e8c, 0x3c010001, 0xac3b6ebc, 0x3c010001,
-0xac376ec0, 0x3c010001, 0xac3a6ea0, 0xc002b3b,
-0x24052400, 0x8f820200, 0xafa20010, 0x8f820220,
-0xafa20014, 0x8f860044, 0x8f870050, 0x3c040001,
-0x24846008, 0xc002b3b, 0x24052500, 0x8f830060,
-0x74100b, 0x242000a, 0x200f821, 0x0,
-0xd, 0x8fbf0060, 0x8fbe005c, 0x8fb50058,
-0x8fb30054, 0x8fb20050, 0x8fb1004c, 0x8fb00048,
-0x3e00008, 0x27bd0068, 0x27bdffe0, 0x3c040001,
-0x24846014, 0x24052600, 0x3021, 0x3821,
-0xafbf0018, 0xafa00010, 0xc002b3b, 0xafa00014,
-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008,
-0x0, 0x3e00008, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x3e00008, 0x0, 0x3e00008, 0x0,
-0x27bdfde0, 0x27a50018, 0x3c04dead, 0x3484beef,
-0xafbf0218, 0x8f820150, 0x3c03001f, 0x3463ffff,
-0xafa40018, 0xa22823, 0xa32824, 0x8ca20000,
-0x1044000a, 0x0, 0xafa50010, 0x8ca20000,
-0xafa20014, 0x8f860150, 0x8f870250, 0x3c040001,
-0x2484601c, 0xc002b3b, 0x24052700, 0x8fbf0218,
-0x3e00008, 0x27bd0220, 0x27bdffe0, 0x3c06abba,
-0x34c6babe, 0xafb00018, 0x3c100004, 0x3c07007f,
-0x34e7ffff, 0xafbf001c, 0x102840, 0x8e040000,
-0x8ca30000, 0xaca00000, 0xae060000, 0x8ca20000,
-0xaca30000, 0x10460005, 0xae040000, 0xa08021,
-0xf0102b, 0x1040fff5, 0x102840, 0x3c040001,
-0x24846028, 0x24052800, 0x2003021, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x2001021,
-0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
-0x8c020224, 0x3047003f, 0x10e00010, 0x803021,
-0x2821, 0x24030020, 0xe31024, 0x10400002,
-0x63042, 0xa62821, 0x31842, 0x1460fffb,
-0xe31024, 0x2402f000, 0xa22824, 0x3402ffff,
-0x45102b, 0x14400003, 0x3c020001, 0x10000008,
-0x3c020001, 0x3442ffff, 0x851823, 0x43102b,
-0x14400003, 0xa01021, 0x3c02fffe, 0x821021,
-0x3e00008, 0x0, 0x27bdffd0, 0xafb50028,
-0x8fb50040, 0xafb20020, 0xa09021, 0xafb1001c,
-0x24c60003, 0xafbf002c, 0xafb30024, 0xafb00018,
-0x8ea20000, 0x2403fffc, 0xc38024, 0x50102b,
-0x1440001b, 0xe08821, 0x8e330000, 0xafb00010,
-0x8ea20000, 0xafa20014, 0x8e270000, 0x24053000,
-0xc002b3b, 0x2403021, 0x8e230000, 0x702021,
-0x64102b, 0x10400007, 0x2402821, 0x8ca20000,
-0xac620000, 0x24630004, 0x64102b, 0x1440fffb,
-0x24a50004, 0x8ea20000, 0x501023, 0xaea20000,
-0x8e220000, 0x501021, 0x1000000b, 0xae220000,
-0x2402002d, 0xa0820000, 0xafb00010, 0x8ea20000,
-0x2409821, 0xafa20014, 0x8e270000, 0x24053100,
-0xc002b3b, 0x2603021, 0x2601021, 0x8fbf002c,
-0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
-0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe8,
-0x3c1cc000, 0x3c05fffe, 0x3c030001, 0x8c636e84,
-0x3c040001, 0x8c846e90, 0x34a5bf08, 0x24021ffc,
-0x3c010001, 0xac226cd0, 0x3c0200c0, 0x3c010001,
-0xac226cd4, 0x3c020020, 0xafbf0010, 0x3c0100c0,
-0xac201ffc, 0x431023, 0x441023, 0x245bb000,
-0x365b821, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021,
-0x3c0400c0, 0x34840200, 0x3c1a00c0, 0x3c0300c0,
-0x346307c8, 0x24021dfc, 0x3c010001, 0xac226cd0,
-0x24021834, 0x3c010001, 0xac246cd4, 0x3c010001,
-0xac226cd0, 0x3c010001, 0xac236cd4, 0xc00180d,
-0x375a0200, 0x8fbf0010, 0x3e00008, 0x27bd0018,
-0x27bdffc8, 0x3c040001, 0x24846034, 0x24053200,
-0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
-0x3021, 0x3603821, 0xafbf0030, 0xafb3002c,
-0xafb20028, 0xafb10024, 0xafb00020, 0xafa2001c,
-0xafa30018, 0xafb70010, 0xc002b3b, 0xafba0014,
-0xc001916, 0x0, 0x8f820240, 0x34420004,
-0xaf820240, 0x24020001, 0xaf420000, 0x3c020001,
-0x571021, 0x904240f4, 0x10400092, 0x2403fffc,
-0x3c100001, 0x2610ac73, 0x3c120001, 0x2652a84c,
-0x2121023, 0x438024, 0x8fa3001c, 0x3c040001,
-0x24846040, 0x70102b, 0x1440001a, 0x27b30018,
-0x8fb10018, 0x24053000, 0x2403021, 0xafb00010,
-0xafa30014, 0xc002b3b, 0x2203821, 0x8fa30018,
-0x702021, 0x64102b, 0x10400007, 0x2403021,
-0x8cc20000, 0xac620000, 0x24630004, 0x64102b,
-0x1440fffb, 0x24c60004, 0x8fa2001c, 0x501023,
-0xafa2001c, 0x8e620000, 0x501021, 0x1000000a,
-0xae620000, 0x2408821, 0x24053100, 0xafb00010,
-0xafa30014, 0x8fa70018, 0x2203021, 0x2402002d,
-0xc002b3b, 0xa0820000, 0x24070020, 0x8fa3001c,
-0x3c040001, 0x2484605c, 0x24120020, 0x3c010001,
-0xac316eb0, 0x2c620020, 0x1440001d, 0x27b10018,
-0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f50,
-0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821,
-0x8fa30018, 0x3c040001, 0x24846f50, 0x24650020,
-0x65102b, 0x10400007, 0x0, 0x8c820000,
-0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
-0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
-0x8e220000, 0x521021, 0x1000000b, 0xae220000,
-0x3c100001, 0x26106f50, 0x24053100, 0xafa70010,
-0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
-0xc002b3b, 0xa0820000, 0x24070020, 0x3c040001,
-0x24846070, 0x8fa3001c, 0x24120020, 0x3c010001,
-0xac306ee4, 0x2c620020, 0x1440001d, 0x27b10018,
-0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f70,
-0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821,
-0x8fa30018, 0x3c040001, 0x24846f70, 0x24650020,
-0x65102b, 0x10400007, 0x0, 0x8c820000,
-0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
-0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
-0x8e220000, 0x521021, 0x1000000b, 0xae220000,
-0x3c100001, 0x26106f70, 0x24053100, 0xafa70010,
-0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
-0xc002b3b, 0xa0820000, 0x3c010001, 0x10000031,
-0xac306ee0, 0x3c100001, 0x2610821f, 0x3c120001,
-0x2652809c, 0x2121023, 0x438024, 0x8fa3001c,
-0x3c040001, 0x24846084, 0x70102b, 0x1440001a,
-0x27b30018, 0x8fb10018, 0x24053000, 0x2403021,
-0xafb00010, 0xafa30014, 0xc002b3b, 0x2203821,
-0x8fa30018, 0x702021, 0x64102b, 0x10400007,
-0x2403021, 0x8cc20000, 0xac620000, 0x24630004,
-0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c,
-0x501023, 0xafa2001c, 0x8e620000, 0x501021,
-0x1000000a, 0xae620000, 0x2408821, 0x24053100,
-0xafb00010, 0xafa30014, 0x8fa70018, 0x2203021,
-0x2402002d, 0xc002b3b, 0xa0820000, 0x3c010001,
-0xac316eb0, 0x3c030001, 0x8c636eb0, 0x24020400,
-0x60f809, 0xaf820070, 0x8fbf0030, 0x8fb3002c,
-0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
-0x27bd0038, 0x0, 0x0, 0x8f820040,
-0x3c03f000, 0x431024, 0x3c036000, 0x14430006,
-0x0, 0x8f820050, 0x2403ff80, 0x431024,
-0x34420055, 0xaf820050, 0x8f820054, 0x244203e8,
-0xaf820058, 0x240201f4, 0xaf4200e0, 0x24020004,
-0xaf4200e8, 0x24020002, 0xaf4001b0, 0xaf4000e4,
-0xaf4200dc, 0xaf4000d8, 0xaf4000d4, 0x3e00008,
-0xaf4000d0, 0x8f820054, 0x24420005, 0x3e00008,
-0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054,
-0x244203e8, 0xaf820058, 0x3c020800, 0x2c21024,
-0x10400004, 0x3c02f7ff, 0x3442ffff, 0x2c2b024,
-0x36940040, 0x3c020001, 0x8c426da8, 0x10400017,
-0x3c020200, 0x3c030001, 0x8c636f1c, 0x10600016,
-0x282a025, 0x3c020001, 0x8c426e44, 0x14400012,
-0x3c020200, 0x3c020001, 0x8c426d94, 0x30420003,
-0x1440000d, 0x3c020200, 0x8f830224, 0x3c020002,
-0x8c428fec, 0x10620008, 0x3c020200, 0xc003daf,
-0x0, 0x10000004, 0x3c020200, 0xc004196,
-0x0, 0x3c020200, 0x2c21024, 0x10400003,
-0x0, 0xc001f4b, 0x0, 0x8f4200d8,
-0x8f4300dc, 0x24420001, 0xaf4200d8, 0x43102b,
-0x14400003, 0x0, 0xaf4000d8, 0x36940080,
-0x8c030238, 0x1060000c, 0x0, 0x8f4201b0,
-0x244203e8, 0xaf4201b0, 0x43102b, 0x14400006,
-0x0, 0x934205c5, 0x14400003, 0x0,
-0xc001da0, 0x0, 0x8fbf0010, 0x3e00008,
-0x27bd0018, 0x3e00008, 0x0, 0x27bdffd8,
-0xafbf0020, 0x8f43002c, 0x8f420038, 0x10620059,
-0x0, 0x3c020001, 0x571021, 0x904240f0,
-0x10400026, 0x24070008, 0x8f440170, 0x8f450174,
-0x8f48000c, 0x8f860120, 0x24020020, 0xafa20010,
-0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
-0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
-0x370821, 0xa02240f0, 0x8f820124, 0xafa20010,
-0x8f820128, 0x3c040001, 0x24846128, 0xafa20014,
-0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b,
-0x34a50900, 0x1000005c, 0x0, 0x8f420300,
-0x24420001, 0xaf420300, 0x8f420300, 0x8f42002c,
-0xa34005c1, 0x10000027, 0xaf420038, 0x8f440170,
-0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
-0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
-0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
-0x24020001, 0x3c010001, 0x370821, 0xa02240f1,
-0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
-0x24846134, 0xafa20014, 0x8f46002c, 0x8f870120,
-0x3c050009, 0xc002b3b, 0x34a51100, 0x10000036,
-0x0, 0x8f420300, 0x8f43002c, 0x24420001,
-0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1,
-0xaf430038, 0x3c010001, 0x370821, 0xa02040f1,
-0x3c010001, 0x370821, 0xa02040f0, 0x10000026,
-0xaf400034, 0x934205c1, 0x1040001d, 0x0,
-0xa34005c1, 0x8f820040, 0x30420001, 0x14400008,
-0x2021, 0x8c030104, 0x24020001, 0x50620005,
-0x24040001, 0x8c020264, 0x10400003, 0x801021,
-0x24040001, 0x801021, 0x10400006, 0x0,
-0x8f42030c, 0x24420001, 0xaf42030c, 0x10000008,
-0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044,
-0x8f420308, 0x24420001, 0xaf420308, 0x8f420308,
-0x3c010001, 0x370821, 0xa02040f0, 0x3c010001,
-0x370821, 0xa02040f1, 0x8f420000, 0x10400007,
-0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
-0x0, 0x10000005, 0x0, 0xaf800048,
-0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
-0x3c03ff7f, 0x3463ffff, 0x431024, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x10000002,
-0xaf80004c, 0xaf800048, 0x8fbf0020, 0x3e00008,
-0x27bd0028, 0x3e00008, 0x0, 0x27bdffd8,
-0xafbf0020, 0x8f430044, 0x8f42007c, 0x10620029,
-0x24070008, 0x8f440168, 0x8f45016c, 0x8f48000c,
-0x8f860120, 0x24020040, 0xafa20010, 0xafa30014,
-0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x14400011, 0x24020001, 0x3c010001, 0x370821,
-0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128,
-0x3c040001, 0x2484613c, 0xafa20014, 0x8f460044,
-0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51300,
-0x1000000f, 0x0, 0x8f420304, 0x24420001,
-0xaf420304, 0x8f420304, 0x8f420044, 0xaf42007c,
-0x3c010001, 0x370821, 0xa02040f2, 0x10000004,
-0xaf400078, 0x3c010001, 0x370821, 0xa02040f2,
-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x3c03feff, 0x3463ffff,
-0x431024, 0xaf820060, 0x8f420000, 0x10400003,
-0x0, 0x10000002, 0xaf80004c, 0xaf800048,
-0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008,
-0x0, 0x3c020001, 0x8c426da8, 0x27bdffa8,
-0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044,
-0xafb20040, 0xafb1003c, 0xafb00038, 0x104000d5,
-0x8f900044, 0x8f4200d0, 0x24430001, 0x2842000b,
-0x144000e4, 0xaf4300d0, 0x8f420004, 0x30420002,
-0x1440009c, 0xaf4000d0, 0x8f420004, 0x3c030001,
-0x8c636d98, 0x34420002, 0xaf420004, 0x24020001,
-0x14620003, 0x3c020600, 0x10000002, 0x34423000,
-0x34421000, 0xafa20020, 0x8f4a0018, 0xafaa0034,
-0x27aa0020, 0xafaa002c, 0x8faa0034, 0x240200ff,
-0x11420002, 0x1821, 0x25430001, 0x8c020228,
-0x609821, 0x1662000e, 0x3c050009, 0x8f42033c,
-0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
-0x8fa70034, 0x3c040001, 0x2484610c, 0xafa00014,
-0xafa20010, 0x8fa60020, 0x10000070, 0x34a50500,
-0x8faa0034, 0xa38c0, 0xf71021, 0x8fa30020,
-0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054,
-0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9,
-0x1040001b, 0xa821, 0xe09021, 0x265e04c0,
-0x8f440178, 0x8f45017c, 0x2401821, 0x240a0004,
-0xafaa0010, 0xafb30014, 0x8f48000c, 0x1021,
-0x2fe3021, 0xafa80018, 0x8f48010c, 0x24070008,
-0xa32821, 0xa3482b, 0x822021, 0x100f809,
-0x892021, 0x54400006, 0x24150001, 0x8f820054,
-0x2221023, 0x2c4203e9, 0x1440ffe9, 0x0,
-0x32a200ff, 0x54400018, 0xaf530018, 0x8f420378,
-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
-0x8faa002c, 0x8fa70034, 0xafa20010, 0x8f820124,
-0x3c040001, 0x24846118, 0xafa20014, 0x8d460000,
-0x3c050009, 0x10000035, 0x34a50600, 0x8f420308,
-0x24150001, 0x24420001, 0xaf420308, 0x8f420308,
-0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054,
-0x247103e8, 0x2221023, 0x2c4203e9, 0x10400016,
-0xa821, 0x3c1e0020, 0x24120010, 0x8f42000c,
-0x8f440160, 0x8f450164, 0x8f860120, 0xafb20010,
-0xafb30014, 0x5e1025, 0xafa20018, 0x8f42010c,
-0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3,
-0x0, 0x8f820054, 0x2221023, 0x2c4203e9,
-0x1440ffee, 0x0, 0x32a200ff, 0x14400011,
-0x3c050009, 0x8f420378, 0x24420001, 0xaf420378,
-0x8f420378, 0x8f820120, 0x8faa002c, 0x8fa70034,
-0xafa20010, 0x8f820124, 0x3c040001, 0x24846120,
-0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
-0x0, 0x8f4202ec, 0x24420001, 0xaf4202ec,
-0x8f4202ec, 0x8f420004, 0x30420001, 0x50400029,
-0x36100040, 0x3c020400, 0x2c21024, 0x10400013,
-0x2404ffdf, 0x8f420250, 0x8f430254, 0x8f4401b4,
-0x14640006, 0x36100040, 0x8f420270, 0x8f430274,
-0x8f4401b8, 0x10640007, 0x2402ffdf, 0x8f420250,
-0x8f430254, 0x8f440270, 0x8f450274, 0x10000012,
-0x3a100020, 0x1000002b, 0x2028024, 0x8f420250,
-0x8f430254, 0x8f4501b4, 0x14650006, 0x2048024,
-0x8f420270, 0x8f430274, 0x8f4401b8, 0x50640021,
-0x36100040, 0x8f420250, 0x8f430254, 0x8f440270,
-0x8f450274, 0x3a100040, 0xaf4301b4, 0x10000019,
-0xaf4501b8, 0x8f4200d4, 0x24430001, 0x10000011,
-0x28420033, 0x8f420004, 0x30420001, 0x10400009,
-0x3c020400, 0x2c21024, 0x10400004, 0x2402ffdf,
-0x2028024, 0x1000000b, 0x36100040, 0x10000009,
-0x36100060, 0x8f4200d4, 0x36100040, 0x24430001,
-0x284201f5, 0x14400003, 0xaf4300d4, 0xaf4000d4,
-0x3a100020, 0xaf900044, 0x2402ff7f, 0x282a024,
-0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044,
-0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008,
-0x27bd0058, 0x3e00008, 0x0, 0x3c020001,
-0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
-0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
-0x104000c7, 0xafb00030, 0x8f4200d0, 0x24430001,
-0x2842000b, 0x144000da, 0xaf4300d0, 0x8f420004,
-0x30420002, 0x14400097, 0xaf4000d0, 0x8f420004,
-0x3c030001, 0x8c636d98, 0x34420002, 0xaf420004,
-0x24020001, 0x14620003, 0x3c020600, 0x10000002,
-0x34423000, 0x34421000, 0xafa20020, 0x1821,
-0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
-0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
-0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
-0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010,
-0x8fa60020, 0x1000006d, 0x34a50500, 0xf71021,
-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
-0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
-0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
-0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
-0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
-0x24070008, 0xa32821, 0xa3482b, 0x822021,
-0x100f809, 0x892021, 0x54400006, 0x24130001,
-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
-0x0, 0x326200ff, 0x54400017, 0xaf520018,
-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
-0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
-0x3c040001, 0x24846118, 0x3c050009, 0xafa20014,
-0x8d460000, 0x10000035, 0x34a50600, 0x8f420308,
-0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
-0x1000001e, 0x326200ff, 0x8f830054, 0x8f820054,
-0x247003e8, 0x2021023, 0x2c4203e9, 0x10400016,
-0x9821, 0x3c150020, 0x24110010, 0x8f42000c,
-0x8f440160, 0x8f450164, 0x8f860120, 0xafb10010,
-0xafb20014, 0x551025, 0xafa20018, 0x8f42010c,
-0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3,
-0x0, 0x8f820054, 0x2021023, 0x2c4203e9,
-0x1440ffee, 0x0, 0x326200ff, 0x14400011,
-0x0, 0x8f420378, 0x24420001, 0xaf420378,
-0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24846120, 0x3c050009,
-0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
-0x3c03821, 0x8f4202ec, 0x24420001, 0xaf4202ec,
-0x8f4202ec, 0x8f420004, 0x30420001, 0x10400018,
-0x24040001, 0x8f420250, 0x8f430254, 0x8f4501b4,
-0x3c010001, 0x14650006, 0xa0246cf1, 0x8f420270,
-0x8f430274, 0x8f4401b8, 0x10640021, 0x0,
-0x8f420250, 0x8f430254, 0x3c040001, 0x90846cf0,
-0x8f460270, 0x8f470274, 0x38840001, 0xaf4301b4,
-0xaf4701b8, 0x3c010001, 0x10000025, 0xa0246cf0,
-0x8f4200d4, 0x3c010001, 0xa0206cf0, 0x24430001,
-0x28420033, 0x1440001e, 0xaf4300d4, 0x3c020001,
-0x90426cf1, 0xaf4000d4, 0x10000017, 0x38420001,
-0x8f420004, 0x30420001, 0x10400008, 0x0,
-0xc00565a, 0x2021, 0x3c010001, 0xa0206cf1,
-0x3c010001, 0x1000000e, 0xa0206cf0, 0x8f4200d4,
-0x3c010001, 0xa0206cf0, 0x24430001, 0x284201f5,
-0x14400007, 0xaf4300d4, 0x3c020001, 0x90426cf1,
-0xaf4000d4, 0x421026, 0x3c010001, 0xa0226cf1,
-0x3c030001, 0x8c636d98, 0x24020002, 0x1462000c,
-0x3c030002, 0x3c030001, 0x90636cf1, 0x24020001,
-0x5462001f, 0x2021, 0x3c020001, 0x90426cf0,
-0x1443001b, 0x24040005, 0x10000019, 0x24040006,
-0x3c020002, 0x8c428ff4, 0x431024, 0x1040000b,
-0x24020001, 0x3c030001, 0x90636cf1, 0x54620010,
-0x2021, 0x3c020001, 0x90426cf0, 0x1443000c,
-0x24040003, 0x1000000a, 0x24040004, 0x3c030001,
-0x90636cf1, 0x14620006, 0x2021, 0x3c020001,
-0x90426cf0, 0x24040001, 0x50440001, 0x24040002,
-0xc00565a, 0x0, 0x2402ff7f, 0x282a024,
-0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
-0x27bd0050, 0x3e00008, 0x0, 0x3c020001,
-0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
-0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
-0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040001,
-0x8c846d98, 0x24430001, 0x2842000b, 0xaf4400e8,
-0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002,
-0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002,
-0xaf420004, 0x24020001, 0x14820003, 0x3c020600,
-0x10000002, 0x34423000, 0x34421000, 0xafa20020,
-0x1821, 0x8f5e0018, 0x27aa0020, 0x240200ff,
-0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228,
-0x609021, 0x1642000e, 0x1e38c0, 0x8f42033c,
-0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
-0x3c040001, 0x2484610c, 0x3c050009, 0xafa00014,
-0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500,
-0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0,
-0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8,
-0x2021023, 0x2c4203e9, 0x1040001b, 0x9821,
-0xe08821, 0x263504c0, 0x8f440178, 0x8f45017c,
-0x2201821, 0x240a0004, 0xafaa0010, 0xafb20014,
-0x8f48000c, 0x1021, 0x2f53021, 0xafa80018,
-0x8f48010c, 0x24070008, 0xa32821, 0xa3482b,
-0x822021, 0x100f809, 0x892021, 0x54400006,
-0x24130001, 0x8f820054, 0x2021023, 0x2c4203e9,
-0x1440ffe9, 0x0, 0x326200ff, 0x54400017,
-0xaf520018, 0x8f420378, 0x24420001, 0xaf420378,
-0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24846118, 0x3c050009,
-0xafa20014, 0x8d460000, 0x10000035, 0x34a50600,
-0x8f420308, 0x24130001, 0x24420001, 0xaf420308,
-0x8f420308, 0x1000001e, 0x326200ff, 0x8f830054,
-0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9,
-0x10400016, 0x9821, 0x3c150020, 0x24110010,
-0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
-0xafb10010, 0xafb20014, 0x551025, 0xafa20018,
-0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c,
-0x1440ffe3, 0x0, 0x8f820054, 0x2021023,
-0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff,
-0x14400011, 0x0, 0x8f420378, 0x24420001,
-0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
-0xafa20010, 0x8f820124, 0x3c040001, 0x24846120,
-0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700,
-0xc002b3b, 0x3c03821, 0x8f4202ec, 0x24420001,
-0xaf4202ec, 0x8f4202ec, 0x8f420004, 0x30420001,
-0x10400033, 0x3c020400, 0x2c21024, 0x10400017,
-0x0, 0x934205c0, 0x8f440250, 0x8f450254,
-0x8f4301b4, 0x34420020, 0x14a30006, 0xa34205c0,
-0x8f420270, 0x8f430274, 0x8f4401b8, 0x10640008,
-0x0, 0x8f420250, 0x8f430254, 0x934405c0,
-0x8f460270, 0x8f470274, 0x10000016, 0x38840040,
-0x934205c0, 0x10000048, 0x304200bf, 0x934205c0,
-0x8f440250, 0x8f450254, 0x8f4301b4, 0x304200bf,
-0x14a30006, 0xa34205c0, 0x8f420270, 0x8f430274,
-0x8f4401b8, 0x1064000b, 0x0, 0x8f420250,
-0x8f430254, 0x934405c0, 0x8f460270, 0x8f470274,
-0x38840020, 0xaf4301b4, 0xaf4701b8, 0x10000033,
-0xa34405c0, 0x934205c0, 0x1000002f, 0x34420020,
-0x934205c0, 0x8f4300d4, 0x34420020, 0xa34205c0,
-0x24620001, 0x10000023, 0x28630033, 0x8f4200e4,
-0x8f4300e0, 0x24420001, 0xaf4200e4, 0x43102a,
-0x14400006, 0x24030001, 0x8f4200e8, 0x14430002,
-0xaf4000e4, 0x24030004, 0xaf4300e8, 0x8f420004,
-0x30420001, 0x1040000d, 0x3c020400, 0x2c21024,
-0x10400007, 0x0, 0x934205c0, 0x34420040,
-0xa34205c0, 0x934205c0, 0x1000000f, 0x304200df,
-0x934205c0, 0x1000000c, 0x34420060, 0x934205c0,
-0x8f4300d4, 0x34420020, 0xa34205c0, 0x24620001,
-0x286300fb, 0x14600005, 0xaf4200d4, 0x934205c0,
-0xaf4000d4, 0x38420040, 0xa34205c0, 0x934205c0,
-0x8f4300e8, 0x3042007f, 0xa34205c0, 0x24020001,
-0x14620005, 0x0, 0x934405c0, 0x42102,
-0x10000003, 0x348400f0, 0x934405c0, 0x3484000f,
-0xc005640, 0x0, 0x2402ff7f, 0x282a024,
-0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
-0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0,
-0x274401c0, 0x26e30028, 0x24650400, 0x65102b,
-0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c,
-0xafb20038, 0xafb10034, 0x10400007, 0xafb00030,
-0x8c820000, 0xac620000, 0x24630004, 0x65102b,
-0x1440fffb, 0x24840004, 0x8c020080, 0xaee20044,
-0x8c0200c0, 0xaee20040, 0x8c020084, 0xaee20030,
-0x8c020084, 0xaee2023c, 0x8c020088, 0xaee20240,
-0x8c02008c, 0xaee20244, 0x8c020090, 0xaee20248,
-0x8c020094, 0xaee2024c, 0x8c020098, 0xaee20250,
-0x8c02009c, 0xaee20254, 0x8c0200a0, 0xaee20258,
-0x8c0200a4, 0xaee2025c, 0x8c0200a8, 0xaee20260,
-0x8c0200ac, 0xaee20264, 0x8c0200b0, 0xaee20268,
-0x8c0200b4, 0xaee2026c, 0x8c0200b8, 0xaee20270,
-0x8c0200bc, 0x24040001, 0xaee20274, 0xaee00034,
-0x41080, 0x571021, 0x8ee30034, 0x8c42023c,
-0x24840001, 0x621821, 0x2c82000f, 0xaee30034,
-0x1440fff8, 0x41080, 0x8c0200cc, 0xaee20048,
-0x8c0200d0, 0xaee2004c, 0x8c0200e0, 0xaee201f8,
-0x8c0200e4, 0xaee201fc, 0x8c0200e8, 0xaee20200,
-0x8c0200ec, 0xaee20204, 0x8c0200f0, 0xaee20208,
-0x8ee400c0, 0x8ee500c4, 0x8c0200fc, 0x45102b,
-0x1040000b, 0x0, 0x8ee200c0, 0x8ee300c4,
-0x24040001, 0x24050000, 0x651821, 0x65302b,
-0x441021, 0x461021, 0xaee200c0, 0xaee300c4,
-0x8c0200fc, 0x8ee400c0, 0x8ee500c4, 0x2408ffff,
-0x24090000, 0x401821, 0x1021, 0x882024,
-0xa92824, 0x822025, 0xa32825, 0xaee400c0,
-0xaee500c4, 0x8ee400d0, 0x8ee500d4, 0x8c0200f4,
-0x45102b, 0x1040000b, 0x0, 0x8ee200d0,
-0x8ee300d4, 0x24040001, 0x24050000, 0x651821,
-0x65302b, 0x441021, 0x461021, 0xaee200d0,
-0xaee300d4, 0x8c0200f4, 0x8ee400d0, 0x8ee500d4,
-0x401821, 0x1021, 0x882024, 0xa92824,
-0x822025, 0xa32825, 0xaee400d0, 0xaee500d4,
-0x8ee400c8, 0x8ee500cc, 0x8c0200f8, 0x45102b,
-0x1040000b, 0x0, 0x8ee200c8, 0x8ee300cc,
-0x24040001, 0x24050000, 0x651821, 0x65302b,
-0x441021, 0x461021, 0xaee200c8, 0xaee300cc,
-0x8c0200f8, 0x8ee400c8, 0x8ee500cc, 0x401821,
-0x1021, 0x882024, 0xa92824, 0x822025,
-0xa32825, 0x24020008, 0xaee400c8, 0xaee500cc,
-0xafa20010, 0xafa00014, 0x8f42000c, 0x8c040208,
-0x8c05020c, 0xafa20018, 0x8f42010c, 0x26e60028,
-0x40f809, 0x24070400, 0x104000f0, 0x3c020400,
-0xafa20020, 0x934205c6, 0x10400089, 0x1821,
-0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
-0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
-0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
-0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010,
-0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
-0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
-0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
-0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
-0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
-0x24070008, 0xa32821, 0xa3482b, 0x822021,
-0x100f809, 0x892021, 0x54400006, 0x24130001,
-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
-0x0, 0x326200ff, 0x54400017, 0xaf520018,
-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
-0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
-0x3c040001, 0x24846118, 0x3c050009, 0xafa20014,
-0x8d460000, 0x10000033, 0x34a50600, 0x8f420308,
-0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
-0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
-0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
-0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
-0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
-0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
-0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
-0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
-0x326200ff, 0x54400012, 0x24020001, 0x8f420378,
-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
-0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24846120, 0x3c050009, 0xafa20014, 0x8d460000,
-0x34a50700, 0xc002b3b, 0x3c03821, 0x1021,
-0x1440005b, 0x24020001, 0x10000065, 0x0,
-0x8f510018, 0x240200ff, 0x12220002, 0x8021,
-0x26300001, 0x8c020228, 0x1602000e, 0x1130c0,
-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
-0x8c020228, 0x3c040001, 0x248460f4, 0x3c050009,
-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f,
-0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024,
-0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
-0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
-0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021,
-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
-0xa3482b, 0x822021, 0x100f809, 0x892021,
-0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x248460fc, 0x3c050009,
-0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200,
-0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018,
-0x8f860120, 0x24020010, 0xafa20010, 0xafb00014,
-0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x54400011, 0x24020001, 0x8f420340, 0x24420001,
-0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24846104, 0x3c050009,
-0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b,
-0x2203821, 0x1021, 0x1040000d, 0x24020001,
-0x8f4202e8, 0xa34005c6, 0xaf4001b0, 0x24420001,
-0xaf4202e8, 0x8f4202e8, 0x8ee20150, 0x24420001,
-0xaee20150, 0x10000003, 0x8ee20150, 0x24020001,
-0xa34205c6, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
-0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
-0x3e00008, 0x27bd0050, 0x27bdffd8, 0xafbf0020,
-0x8f8200b0, 0x30420004, 0x10400068, 0x0,
-0x8f430128, 0x8f820104, 0x14620005, 0x0,
-0x8f430130, 0x8f8200b4, 0x10620006, 0x0,
-0x8f820104, 0xaf420128, 0x8f8200b4, 0x1000005b,
-0xaf420130, 0x8f8200b0, 0x3c030080, 0x431024,
-0x1040000d, 0x0, 0x8f82011c, 0x34420002,
-0xaf82011c, 0x8f8200b0, 0x2403fffb, 0x431024,
-0xaf8200b0, 0x8f82011c, 0x2403fffd, 0x431024,
-0x1000004a, 0xaf82011c, 0x8f430128, 0x8f820104,
-0x14620005, 0x0, 0x8f430130, 0x8f8200b4,
-0x10620010, 0x0, 0x8f820104, 0xaf420128,
-0x8f8200b4, 0x8f430128, 0xaf420130, 0xafa30010,
-0x8f420130, 0x3c040001, 0x24846144, 0xafa20014,
-0x8f86011c, 0x8f8700b0, 0x3c050005, 0x10000031,
-0x34a50900, 0x8f420128, 0xafa20010, 0x8f420130,
-0x3c040001, 0x24846150, 0xafa20014, 0x8f86011c,
-0x8f8700b0, 0x3c050005, 0xc002b3b, 0x34a51000,
-0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104,
-0x8f8200b0, 0x34420001, 0xaf8200b0, 0x24020008,
-0xaf830104, 0xafa20010, 0xafa00014, 0x8f42000c,
-0x8c040208, 0x8c05020c, 0xafa20018, 0x8f42010c,
-0x26e60028, 0x40f809, 0x24070400, 0x8f82011c,
-0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc,
-0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420128,
-0xafa20010, 0x8f420130, 0x3c040001, 0x2484615c,
-0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005,
-0x34a51100, 0xc002b3b, 0x0, 0x8f8200a0,
-0x30420004, 0x10400069, 0x0, 0x8f43012c,
-0x8f820124, 0x14620005, 0x0, 0x8f430134,
-0x8f8200a4, 0x10620006, 0x0, 0x8f820124,
-0xaf42012c, 0x8f8200a4, 0x1000005c, 0xaf420134,
-0x8f8200a0, 0x3c030080, 0x431024, 0x1040000d,
-0x0, 0x8f82011c, 0x34420002, 0xaf82011c,
-0x8f8200a0, 0x2403fffb, 0x431024, 0xaf8200a0,
-0x8f82011c, 0x2403fffd, 0x431024, 0x1000004b,
-0xaf82011c, 0x8f43012c, 0x8f820124, 0x14620005,
-0x0, 0x8f430134, 0x8f8200a4, 0x10620010,
-0x0, 0x8f820124, 0xaf42012c, 0x8f8200a4,
-0x8f43012c, 0xaf420134, 0xafa30010, 0x8f420134,
-0x3c040001, 0x24846168, 0xafa20014, 0x8f86011c,
-0x8f8700a0, 0x3c050005, 0x10000032, 0x34a51200,
-0x8f42012c, 0xafa20010, 0x8f420134, 0x3c040001,
-0x24846174, 0xafa20014, 0x8f86011c, 0x8f8700a0,
-0x3c050005, 0xc002b3b, 0x34a51300, 0x8f82011c,
-0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0,
-0x34420001, 0xaf8200a0, 0x24020080, 0xaf830124,
-0xafa20010, 0xafa00014, 0x8f420014, 0x8c040208,
-0x8c05020c, 0xafa20018, 0x8f420108, 0x3c060001,
-0x24c66ed8, 0x40f809, 0x24070004, 0x8f82011c,
-0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc,
-0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f42012c,
-0xafa20010, 0x8f420134, 0x3c040001, 0x24846180,
-0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005,
-0x34a51400, 0xc002b3b, 0x0, 0x8fbf0020,
-0x3e00008, 0x27bd0028, 0x3c081000, 0x24070001,
-0x3c060080, 0x3c050100, 0x8f820070, 0x481024,
-0x1040fffd, 0x0, 0x8f820054, 0x24420005,
-0xaf820078, 0x8c040234, 0x10800016, 0x1821,
-0x3c020001, 0x571021, 0x8c4240e8, 0x24420005,
-0x3c010001, 0x370821, 0xac2240e8, 0x3c020001,
-0x571021, 0x8c4240e8, 0x44102b, 0x14400009,
-0x0, 0x3c030080, 0x3c010001, 0x370821,
-0xac2040e8, 0x3c010001, 0x370821, 0x1000000b,
-0xa02740f0, 0x3c020001, 0x571021, 0x904240f0,
-0x54400006, 0x661825, 0x3c020001, 0x571021,
-0x904240f1, 0x54400001, 0x661825, 0x8c040230,
-0x10800013, 0x0, 0x3c020001, 0x571021,
-0x8c4240ec, 0x24420005, 0x3c010001, 0x370821,
-0xac2240ec, 0x3c020001, 0x571021, 0x8c4240ec,
-0x44102b, 0x14400006, 0x0, 0x3c010001,
-0x370821, 0xac2040ec, 0x10000006, 0x651825,
-0x3c020001, 0x571021, 0x904240f2, 0x54400001,
-0x651825, 0x1060ffbc, 0x0, 0x8f420000,
-0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x431025, 0xaf820060, 0x8f420000,
-0x10400003, 0x0, 0x1000ffa7, 0xaf80004c,
-0x1000ffa5, 0xaf800048, 0x3e00008, 0x0,
-0x0, 0x0, 0x0, 0x27bdffe0,
-0xafbf0018, 0x8f860064, 0x30c20004, 0x10400025,
-0x24040004, 0x8c020114, 0xaf420020, 0xaf840064,
-0x8f4202fc, 0x24420001, 0xaf4202fc, 0x8f4202fc,
-0x8f820064, 0x30420004, 0x14400005, 0x0,
-0x8c030114, 0x8f420020, 0x1462fff2, 0x0,
-0x8f420000, 0x10400007, 0x8f43003c, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x431025, 0xaf820060,
-0x8f420000, 0x10400073, 0x0, 0x1000006f,
-0x0, 0x30c20008, 0x10400020, 0x24040008,
-0x8c02011c, 0xaf420048, 0xaf840064, 0x8f4202a8,
-0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f820064,
-0x30420008, 0x14400005, 0x0, 0x8c03011c,
-0x8f420048, 0x1462fff2, 0x0, 0x8f420000,
-0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x1000ffd9, 0x34420200, 0x30c20020,
-0x10400023, 0x24040020, 0x8c02012c, 0xaf420068,
-0xaf840064, 0x8f4202d8, 0x24420001, 0xaf4202d8,
-0x8f4202d8, 0x8f820064, 0x30420020, 0x14400005,
-0x32c24000, 0x8c03012c, 0x8f420068, 0x1462fff2,
-0x32c24000, 0x14400002, 0x3c020001, 0x2c2b025,
-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x1000ffb4, 0x34420800,
-0x30c20010, 0x10400029, 0x24040010, 0x8c020124,
-0xaf420058, 0xaf840064, 0x8f4202d4, 0x24420001,
-0xaf4202d4, 0x8f4202d4, 0x8f820064, 0x30420010,
-0x14400005, 0x32c22000, 0x8c030124, 0x8f420058,
-0x1462fff2, 0x32c22000, 0x50400001, 0x36d68000,
-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x34420100, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x1000006c,
-0xaf80004c, 0x1000006a, 0xaf800048, 0x30c20001,
-0x10400004, 0x24020001, 0xaf820064, 0x10000064,
-0x0, 0x30c20002, 0x1440000b, 0x3c050003,
-0x3c040001, 0x24846244, 0x34a50500, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x2402ffc0,
-0x10000057, 0xaf820064, 0x8c05022c, 0x8c02010c,
-0x10a20048, 0x51080, 0x8c460300, 0x24a20001,
-0x3045003f, 0x24020003, 0xac05022c, 0x61e02,
-0x10620005, 0x24020010, 0x1062001d, 0x30c20fff,
-0x10000039, 0x0, 0x8f4302a8, 0x8f440000,
-0x30c20fff, 0xaf420048, 0x24630001, 0xaf4302a8,
-0x10800007, 0x8f4202a8, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x34420200, 0xaf820060, 0x8f420000,
-0x1040001f, 0x0, 0x1000001b, 0x0,
-0xaf420058, 0x32c22000, 0x50400001, 0x36d68000,
-0x8f4202d4, 0x8f430000, 0x24420001, 0xaf4202d4,
-0x10600007, 0x8f4202d4, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x34420100, 0xaf820060, 0x8f420000,
-0x10400003, 0x0, 0x10000006, 0xaf80004c,
-0x10000004, 0xaf800048, 0xc002196, 0xc02021,
-0x402821, 0x8c02010c, 0x14a20002, 0x24020002,
-0xaf820064, 0x8f820064, 0x30420002, 0x14400004,
-0x0, 0x8c02010c, 0x14a2ffac, 0x0,
-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008,
-0x0, 0x27bdffa0, 0xafb00040, 0x808021,
-0x101602, 0x2442ffff, 0x304300ff, 0x2c620013,
-0xafbf0058, 0xafbe0054, 0xafb50050, 0xafb3004c,
-0xafb20048, 0xafb10044, 0x104001f3, 0xafa50034,
-0x31080, 0x3c010001, 0x220821, 0x8c226288,
-0x400008, 0x0, 0x101302, 0x30440fff,
-0x24020001, 0x10820005, 0x24020002, 0x1082000c,
-0x2402fffe, 0x10000024, 0x3c050003, 0x8f430004,
-0x3c020001, 0x8c426f04, 0xaf440200, 0xaf440204,
-0x3c040001, 0x8c846e80, 0x10000009, 0x34630001,
-0x8f430004, 0xaf440200, 0xaf440204, 0x3c040001,
-0x8c846e80, 0x621824, 0x3c020001, 0x2442ca28,
-0x21100, 0x21182, 0xaf430004, 0x3c030800,
-0x431025, 0xac820038, 0x8f840054, 0x41442,
-0x41c82, 0x431021, 0x41cc2, 0x431023,
-0x41d02, 0x431021, 0x41d42, 0x431023,
-0x10000009, 0xaf420208, 0x3c040001, 0x24846250,
-0x34a51000, 0x2003021, 0x3821, 0xafa00010,
-0xc002b3b, 0xafa00014, 0x8f4202a0, 0x24420001,
-0xaf4202a0, 0x1000021f, 0x8f4202a0, 0x27b00028,
-0x2002021, 0x24050210, 0xc002bbf, 0x24060008,
-0xc002518, 0x2002021, 0x10000216, 0x0,
-0x8faa0034, 0x27a40028, 0xa1880, 0x25420001,
-0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034,
-0x21080, 0x8c430300, 0x25420001, 0x3042003f,
-0xafa20034, 0xac02022c, 0xafa50028, 0xc002518,
-0xafa3002c, 0x10000203, 0x0, 0x27b00028,
-0x2002021, 0x24050210, 0xc002bbf, 0x24060008,
-0xc002657, 0x2002021, 0x100001fa, 0x0,
-0x8faa0034, 0x27a40028, 0xa1880, 0x25420001,
-0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034,
-0x21080, 0x8c430300, 0x25420001, 0x3042003f,
-0xafa20034, 0xac02022c, 0xafa50028, 0xc002657,
-0xafa3002c, 0x100001e7, 0x0, 0x101302,
-0x30430fff, 0x24020001, 0x10620005, 0x24020002,
-0x1062001e, 0x3c020002, 0x10000033, 0x3c050003,
-0x3c030002, 0x2c31024, 0x54400037, 0x2c3b025,
-0x8f820228, 0x3c010001, 0x370821, 0xac2238d8,
-0x8f82022c, 0x3c010001, 0x370821, 0xac2238dc,
-0x8f820230, 0x3c010001, 0x370821, 0xac2238e0,
-0x8f820234, 0x3c010001, 0x370821, 0xac2238e4,
-0x2402ffff, 0xaf820228, 0xaf82022c, 0xaf820230,
-0xaf820234, 0x10000020, 0x2c3b025, 0x2c21024,
-0x10400012, 0x3c02fffd, 0x3c020001, 0x571021,
-0x8c4238d8, 0xaf820228, 0x3c020001, 0x571021,
-0x8c4238dc, 0xaf82022c, 0x3c020001, 0x571021,
-0x8c4238e0, 0xaf820230, 0x3c020001, 0x571021,
-0x8c4238e4, 0xaf820234, 0x3c02fffd, 0x3442ffff,
-0x10000009, 0x2c2b024, 0x3c040001, 0x2484625c,
-0x34a51100, 0x2003021, 0x3821, 0xafa00010,
-0xc002b3b, 0xafa00014, 0x8f4202cc, 0x24420001,
-0xaf4202cc, 0x1000019f, 0x8f4202cc, 0x101302,
-0x30450fff, 0x24020001, 0x10a20005, 0x24020002,
-0x10a2000d, 0x3c0408ff, 0x10000014, 0x3c050003,
-0x3c0208ff, 0x3442ffff, 0x8f830220, 0x3c040004,
-0x2c4b025, 0x621824, 0x34630008, 0xaf830220,
-0x10000012, 0xaf450298, 0x3484fff7, 0x3c03fffb,
-0x8f820220, 0x3463ffff, 0x2c3b024, 0x441024,
-0xaf820220, 0x10000009, 0xaf450298, 0x3c040001,
-0x24846268, 0x34a51200, 0x2003021, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202bc,
-0x24420001, 0xaf4202bc, 0x10000176, 0x8f4202bc,
-0x27840208, 0x24050200, 0xc002bbf, 0x24060008,
-0x27440224, 0x24050200, 0xc002bbf, 0x24060008,
-0x8f4202c4, 0x24420001, 0xaf4202c4, 0x10000169,
-0x8f4202c4, 0x101302, 0x30430fff, 0x24020001,
-0x10620011, 0x28620002, 0x50400005, 0x24020002,
-0x10600007, 0x0, 0x10000017, 0x0,
-0x1062000f, 0x0, 0x10000013, 0x0,
-0x8c060248, 0x2021, 0xc005104, 0x24050004,
-0x10000007, 0x0, 0x8c060248, 0x2021,
-0xc005104, 0x24050004, 0x10000010, 0x0,
-0x8c06024c, 0x2021, 0xc005104, 0x24050001,
-0x1000000a, 0x0, 0x3c040001, 0x24846274,
-0x3c050003, 0x34a51300, 0x2003021, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202c0,
-0x24420001, 0xaf4202c0, 0x1000013a, 0x8f4202c0,
-0xc002426, 0x0, 0x10000136, 0x0,
-0x24020001, 0xa34205c5, 0x24100100, 0x8f4401a8,
-0x8f4501ac, 0xafb00010, 0xafa00014, 0x8f420014,
-0xafa20018, 0x8f420108, 0x26e60028, 0x40f809,
-0x24070400, 0x1040fff5, 0x0, 0x10000125,
-0x0, 0x3c03ffff, 0x34637fff, 0x8f420368,
-0x8f440360, 0x2c3b024, 0x1821, 0xaf400058,
-0xaf40005c, 0xaf400060, 0xaf400064, 0x441023,
-0xaf420368, 0x3c020900, 0xaf400360, 0xafa20020,
-0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
-0xafaa003c, 0x27c30001, 0x8c020228, 0x609021,
-0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
-0x2484620c, 0x3c050009, 0xafa00014, 0xafa20010,
-0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
-0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
-0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
-0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
-0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
-0x24070008, 0xa32821, 0xa3482b, 0x822021,
-0x100f809, 0x892021, 0x54400006, 0x24130001,
-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
-0x0, 0x326200ff, 0x54400017, 0xaf520018,
-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
-0x8f820120, 0x8faa003c, 0xafa20010, 0x8f820124,
-0x3c040001, 0x24846218, 0x3c050009, 0xafa20014,
-0x8d460000, 0x10000033, 0x34a50600, 0x8f420308,
-0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
-0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
-0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
-0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
-0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
-0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
-0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
-0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
-0x326200ff, 0x14400011, 0x0, 0x8f420378,
-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
-0x8faa003c, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24846220, 0x3c050009, 0xafa20014, 0x8d460000,
-0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b0,
-0x24420001, 0xaf4202b0, 0x8f4202b0, 0x8f4202f8,
-0x24420001, 0xaf4202f8, 0x1000008a, 0x8f4202f8,
-0x8c02025c, 0x27440224, 0xaf4201f0, 0x8c020260,
-0x24050200, 0x24060008, 0xc002bbf, 0xaf4201f8,
-0x8f820220, 0x30420008, 0x14400002, 0x24020001,
-0x24020002, 0xaf420298, 0x8f4202ac, 0x24420001,
-0xaf4202ac, 0x10000077, 0x8f4202ac, 0x3c0200ff,
-0x3442ffff, 0x2021824, 0x32c20180, 0x14400006,
-0x3402fffb, 0x43102b, 0x14400003, 0x0,
-0x1000006c, 0xaf4300bc, 0x3c040001, 0x24846280,
-0x3c050003, 0x34a51500, 0x2003021, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020700,
-0x34421000, 0x101e02, 0x621825, 0xafa30020,
-0x8f510018, 0x240200ff, 0x12220002, 0x8021,
-0x26300001, 0x8c020228, 0x1602000e, 0x1130c0,
-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
-0x8c020228, 0x3c040001, 0x248461f4, 0x3c050009,
-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f,
-0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024,
-0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
-0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
-0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021,
-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
-0xa3482b, 0x822021, 0x100f809, 0x892021,
-0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x248461fc, 0x3c050009,
-0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200,
-0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018,
-0x8f860120, 0x24020010, 0xafa20010, 0xafb00014,
-0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x14400010, 0x0, 0x8f420340, 0x24420001,
-0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24846204, 0x3c050009,
-0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b,
-0x2203821, 0x8f4202e0, 0x24420001, 0xaf4202e0,
-0x8f4202e0, 0x8f4202f0, 0x24420001, 0xaf4202f0,
-0x8f4202f0, 0x8fa20034, 0x8fbf0058, 0x8fbe0054,
-0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044,
-0x8fb00040, 0x3e00008, 0x27bd0060, 0x27bdfff8,
-0x2408ffff, 0x10a00014, 0x4821, 0x3c0aedb8,
-0x354a8320, 0x90870000, 0x24840001, 0x3021,
-0x1071026, 0x30420001, 0x10400002, 0x81842,
-0x6a1826, 0x604021, 0x24c60001, 0x2cc20008,
-0x1440fff7, 0x73842, 0x25290001, 0x125102b,
-0x1440fff0, 0x0, 0x1001021, 0x3e00008,
-0x27bd0008, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
-0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
-0xafb00030, 0x8f870220, 0xafa70024, 0x8f870200,
-0xafa7002c, 0x8f820220, 0x3c0308ff, 0x3463ffff,
-0x431024, 0x34420004, 0xaf820220, 0x8f820200,
-0x3c03c0ff, 0x3463ffff, 0x431024, 0x34420004,
-0xaf820200, 0x8f530358, 0x8f55035c, 0x8f5e0360,
-0x8f470364, 0xafa70014, 0x8f470368, 0xafa7001c,
-0x8f4202d0, 0x274401c0, 0x24420001, 0xaf4202d0,
-0x8f5002d0, 0x8f510204, 0x8f520200, 0xc002ba8,
-0x24050400, 0xaf530358, 0xaf55035c, 0xaf5e0360,
-0x8fa70014, 0xaf470364, 0x8fa7001c, 0xaf470368,
-0xaf5002d0, 0xaf510204, 0xaf520200, 0x8c02025c,
-0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200,
-0x24060008, 0xaf4201f8, 0x24020006, 0xc002bbf,
-0xaf4201f4, 0x3c023b9a, 0x3442ca00, 0xaf4201fc,
-0x240203e8, 0x24040002, 0x24030001, 0xaf420294,
-0xaf440290, 0xaf43029c, 0x8f820220, 0x30420008,
-0x10400004, 0x0, 0xaf430298, 0x10000003,
-0x3021, 0xaf440298, 0x3021, 0x3c030001,
-0x661821, 0x90636d00, 0x3461021, 0x24c60001,
-0xa043022c, 0x2cc2000f, 0x1440fff8, 0x3461821,
-0x24c60001, 0x8f820040, 0x24040080, 0x24050080,
-0x21702, 0x24420030, 0xa062022c, 0x3461021,
-0xc002ba8, 0xa040022c, 0x8fa70024, 0x30e20004,
-0x14400006, 0x0, 0x8f820220, 0x3c0308ff,
-0x3463fffb, 0x431024, 0xaf820220, 0x8fa7002c,
-0x30e20004, 0x14400006, 0x0, 0x8f820200,
-0x3c03c0ff, 0x3463fffb, 0x431024, 0xaf820200,
-0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
-0x27bd0050, 0x0, 0x0, 0xaf400104,
-0x24040001, 0x410c0, 0x2e21821, 0x24820001,
-0x3c010001, 0x230821, 0xa42234d0, 0x402021,
-0x2c820080, 0x1440fff8, 0x410c0, 0x24020001,
-0x3c010001, 0x370821, 0xa42038d0, 0xaf420100,
-0xaf800228, 0xaf80022c, 0xaf800230, 0xaf800234,
-0x3e00008, 0x0, 0x27bdffe8, 0xafbf0014,
-0xafb00010, 0x8f420104, 0x28420005, 0x10400026,
-0x808021, 0x3c020001, 0x8f430104, 0x344230d0,
-0x2e22021, 0x318c0, 0x621821, 0x2e31821,
-0x83102b, 0x10400015, 0x1021, 0x96070000,
-0x24840006, 0x24660006, 0x9482fffc, 0x14470009,
-0x2821, 0x9483fffe, 0x96020002, 0x14620006,
-0xa01021, 0x94820000, 0x96030004, 0x431026,
-0x2c450001, 0xa01021, 0x14400009, 0x24840008,
-0x86102b, 0x1440fff0, 0x1021, 0x304200ff,
-0x14400030, 0x24020001, 0x1000002e, 0x1021,
-0x1000fffa, 0x24020001, 0x2002021, 0xc00240c,
-0x24050006, 0x3042007f, 0x218c0, 0x2e31021,
-0x3c010001, 0x220821, 0x942230d0, 0x1040fff2,
-0x2e31021, 0x3c060001, 0xc23021, 0x94c630d0,
-0x10c0ffed, 0x3c080001, 0x350834d2, 0x96070000,
-0x610c0, 0x572021, 0x882021, 0x94820000,
-0x14470009, 0x2821, 0x94830002, 0x96020002,
-0x14620006, 0xa01021, 0x94820004, 0x96030004,
-0x431026, 0x2c450001, 0xa01021, 0x14400007,
-0x610c0, 0x2e21021, 0x3c060001, 0xc23021,
-0x94c634d0, 0x14c0ffeb, 0x610c0, 0x10c0ffd2,
-0x24020001, 0x8fbf0014, 0x8fb00010, 0x3e00008,
-0x27bd0018, 0x3e00008, 0x0, 0x27bdffb0,
-0x801021, 0xafb00030, 0x24500002, 0x2002021,
-0x24050006, 0xafb10034, 0x408821, 0xafbf0048,
-0xafbe0044, 0xafb50040, 0xafb3003c, 0xc00240c,
-0xafb20038, 0x3047007f, 0x710c0, 0x2e21021,
-0x3c050001, 0xa22821, 0x94a530d0, 0x50a0001c,
-0xa03021, 0x3c090001, 0x352934d2, 0x96280002,
-0x510c0, 0x572021, 0x892021, 0x94820000,
-0x14480009, 0x3021, 0x94830002, 0x96020002,
-0x14620006, 0xc01021, 0x94820004, 0x96030004,
-0x431026, 0x2c460001, 0xc01021, 0x14400007,
-0x510c0, 0x2e21021, 0x3c050001, 0xa22821,
-0x94a534d0, 0x14a0ffeb, 0x510c0, 0xa03021,
-0x10c00014, 0x610c0, 0x571821, 0x3c010001,
-0x230821, 0x8c2334d0, 0x571021, 0xafa30010,
-0x3c010001, 0x220821, 0x8c2234d4, 0x3c040001,
-0x24846394, 0xafa20014, 0x8e260000, 0x8e270004,
-0x3c050004, 0xc002b3b, 0x34a50400, 0x10000063,
-0x3c020800, 0x8f450100, 0x10a00006, 0x510c0,
-0x2e21021, 0x3c010001, 0x220821, 0x942234d0,
-0xaf420100, 0xa03021, 0x14c00011, 0x628c0,
-0x710c0, 0x2e21021, 0xafa70010, 0x3c010001,
-0x220821, 0x942230d0, 0x3c040001, 0x248463a0,
-0xafa20014, 0x8e260000, 0x8e270004, 0x3c050004,
-0xc002b3b, 0x34a50500, 0x10000048, 0x3c020800,
-0xb71821, 0x3c020001, 0x96040000, 0x344234d2,
-0x621821, 0xa4640000, 0x8e020002, 0x720c0,
-0xac620002, 0x2e41021, 0x3c030001, 0x621821,
-0x946330d0, 0x2e51021, 0x3c010001, 0x220821,
-0xa42334d0, 0x2e41021, 0x3c010001, 0x220821,
-0xa42630d0, 0x8f420104, 0x24420001, 0x28420080,
-0x1040000f, 0x3c020002, 0x8f420104, 0x3c040001,
-0x348430d2, 0x96030000, 0x210c0, 0x571021,
-0x441021, 0xa4430000, 0x8e030002, 0xac430002,
-0x8f420104, 0x24420001, 0xaf420104, 0x3c020002,
-0x2c21024, 0x10400011, 0x72142, 0x3c030001,
-0x346338d8, 0x24020003, 0x441023, 0x21080,
-0x572021, 0x832021, 0x571021, 0x431021,
-0x30e5001f, 0x8c430000, 0x24020001, 0xa21004,
-0x621825, 0x1000000c, 0xac830000, 0x24020003,
-0x441023, 0x21080, 0x5c2821, 0x5c1021,
-0x30e4001f, 0x8c430228, 0x24020001, 0x821004,
-0x621825, 0xaca30228, 0x3c020800, 0x34421000,
-0x1821, 0xafa20020, 0x8f5e0018, 0x27aa0020,
-0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001,
-0x8c020228, 0x609021, 0x1642000e, 0x1e38c0,
-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
-0x8c020228, 0x3c040001, 0x2484635c, 0x3c050009,
-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b,
-0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
-0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
-0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
-0x9821, 0xe08821, 0x263504c0, 0x8f440178,
-0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010,
-0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
-0xa3482b, 0x822021, 0x100f809, 0x892021,
-0x54400006, 0x24130001, 0x8f820054, 0x2021023,
-0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
-0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
-0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
-0xafa20010, 0x8f820124, 0x3c040001, 0x24846368,
-0x3c050009, 0xafa20014, 0x8d460000, 0x10000033,
-0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
-0xaf420308, 0x8f420308, 0x1000001c, 0x326200ff,
-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
-0x2c4203e9, 0x10400014, 0x9821, 0x24110010,
-0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
-0xafb10010, 0xafb20014, 0xafa20018, 0x8f42010c,
-0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe5,
-0x0, 0x8f820054, 0x2021023, 0x2c4203e9,
-0x1440ffef, 0x0, 0x326200ff, 0x14400011,
-0x0, 0x8f420378, 0x24420001, 0xaf420378,
-0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24846370, 0x3c050009,
-0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
-0x3c03821, 0x8f4202b4, 0x24420001, 0xaf4202b4,
-0x8f4202b4, 0x8f4202f4, 0x24420001, 0xaf4202f4,
-0x8f4202f4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
-0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
-0x3e00008, 0x27bd0050, 0x27bdffa0, 0x801021,
-0xafb00040, 0x24500002, 0x2002021, 0x24050006,
-0xafb10044, 0x408821, 0xafbf0058, 0xafbe0054,
-0xafb50050, 0xafb3004c, 0xc00240c, 0xafb20048,
-0x3048007f, 0x810c0, 0x2e21021, 0x3c060001,
-0xc23021, 0x94c630d0, 0x10c0001c, 0x3821,
-0x3c0a0001, 0x354a34d2, 0x96290002, 0x610c0,
-0x572021, 0x8a2021, 0x94820000, 0x14490009,
-0x2821, 0x94830002, 0x96020002, 0x14620006,
-0xa01021, 0x94820004, 0x96030004, 0x431026,
-0x2c450001, 0xa01021, 0x14400008, 0x610c0,
-0xc03821, 0x2e21021, 0x3c060001, 0xc23021,
-0x94c634d0, 0x14c0ffea, 0x610c0, 0x14c00011,
-0xafa70028, 0x810c0, 0x2e21021, 0xafa80010,
-0x3c010001, 0x220821, 0x942230d0, 0x3c040001,
-0x248463ac, 0xafa20014, 0x8e260000, 0x8e270004,
-0x3c050004, 0xc002b3b, 0x34a50900, 0x10000075,
-0x3c020800, 0x10e0000c, 0x610c0, 0x2e21021,
-0x3c030001, 0x621821, 0x946334d0, 0x710c0,
-0x2e21021, 0x3c010001, 0x220821, 0xa42334d0,
-0x1000000b, 0x3c040001, 0x2e21021, 0x3c030001,
-0x621821, 0x946334d0, 0x810c0, 0x2e21021,
-0x3c010001, 0x220821, 0xa42330d0, 0x3c040001,
-0x348430d0, 0x8f430100, 0x610c0, 0x2e21021,
-0x3c010001, 0x220821, 0xa42334d0, 0x8f420104,
-0x2e43821, 0x2821, 0x18400029, 0xaf460100,
-0x24e60006, 0x94c3fffc, 0x96020000, 0x14620009,
-0x2021, 0x94c3fffe, 0x96020002, 0x14620006,
-0x801021, 0x94c20000, 0x96030004, 0x431026,
-0x2c440001, 0x801021, 0x50400014, 0x24a50001,
-0x8f420104, 0x2442ffff, 0xa2102a, 0x1040000b,
-0x24e40004, 0x94820006, 0x8c830008, 0xa482fffe,
-0xac830000, 0x8f420104, 0x24a50001, 0x2442ffff,
-0xa2102a, 0x1440fff7, 0x24840008, 0x8f420104,
-0x2442ffff, 0x10000006, 0xaf420104, 0x8f420104,
-0x24c60008, 0xa2102a, 0x1440ffda, 0x24e70008,
-0x810c0, 0x2e21021, 0x3c010001, 0x220821,
-0x942230d0, 0x14400023, 0x3c020800, 0x3c020002,
-0x2c21024, 0x10400012, 0x82142, 0x3c030001,
-0x346338d8, 0x24020003, 0x441023, 0x21080,
-0x572021, 0x832021, 0x571021, 0x431021,
-0x3105001f, 0x24030001, 0x8c420000, 0xa31804,
-0x31827, 0x431024, 0x1000000d, 0xac820000,
-0x24020003, 0x441023, 0x21080, 0x5c2821,
-0x5c1021, 0x3104001f, 0x24030001, 0x8c420228,
-0x831804, 0x31827, 0x431024, 0xaca20228,
-0x3c020800, 0x34422000, 0x1821, 0xafa20020,
-0x8f5e0018, 0x27ab0020, 0x240200ff, 0x13c20002,
-0xafab0034, 0x27c30001, 0x8c020228, 0x609021,
-0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
-0x2484635c, 0x3c050009, 0xafa00014, 0xafa20010,
-0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
-0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
-0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
-0x240b0004, 0xafab0010, 0xafb20014, 0x8f48000c,
-0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
-0x24070008, 0xa32821, 0xa3482b, 0x822021,
-0x100f809, 0x892021, 0x54400006, 0x24130001,
-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
-0x0, 0x326200ff, 0x54400017, 0xaf520018,
-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
-0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124,
-0x3c040001, 0x24846368, 0x3c050009, 0xafa20014,
-0x8d660000, 0x10000033, 0x34a50600, 0x8f420308,
-0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
-0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
-0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
-0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
-0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
-0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
-0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
-0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
-0x326200ff, 0x14400011, 0x0, 0x8f420378,
-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
-0x8fab0034, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24846370, 0x3c050009, 0xafa20014, 0x8d660000,
-0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b8,
-0x24420001, 0xaf4202b8, 0x8f4202b8, 0x8f4202f4,
-0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8fbf0058,
-0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048,
-0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060,
-0x0, 0x0, 0x0, 0x27bdffe0,
-0x27644000, 0xafbf0018, 0xc002ba8, 0x24051000,
-0x3c030001, 0x34632cc0, 0x3c040001, 0x34842ec8,
-0x24020020, 0xaf82011c, 0x2e31021, 0xaf800100,
-0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114,
-0xaf800118, 0xaf800120, 0xaf800124, 0xaf800128,
-0xaf800130, 0xaf800134, 0xaf800138, 0xaf4200ec,
-0x2e31021, 0xaf4200f0, 0x2e41021, 0xaf4200f4,
-0x2e41021, 0xaf4200f8, 0x3c020001, 0x571021,
-0x904240f4, 0x1440001c, 0x3c050001, 0x8f82011c,
-0x3c040001, 0x24846470, 0x3c050001, 0x34420001,
-0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c,
-0x34a50100, 0xc002b3b, 0x3821, 0x8c020218,
-0x30420040, 0x10400014, 0x0, 0x8f82011c,
-0x3c040001, 0x2484647c, 0x3c050001, 0x34420004,
-0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c,
-0x10000007, 0x34a50200, 0x3c040001, 0x24846484,
-0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50300,
-0xc002b3b, 0x3821, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x8fa90010, 0x8f83012c, 0x8faa0014,
-0x8fab0018, 0x1060000a, 0x27624fe0, 0x14620002,
-0x24680020, 0x27684800, 0x8f820128, 0x11020004,
-0x0, 0x8f820124, 0x15020007, 0x0,
-0x8f430334, 0x1021, 0x24630001, 0xaf430334,
-0x10000039, 0x8f430334, 0xac640000, 0xac650004,
-0xac660008, 0xa467000e, 0xac690018, 0xac6a001c,
-0xac6b0010, 0xac620014, 0xaf880120, 0x8f4200fc,
-0x8f4400f4, 0x2442ffff, 0xaf4200fc, 0x8c820000,
-0x10490005, 0x3042ff8f, 0x10400019, 0x3122ff8f,
-0x10400018, 0x3c020001, 0x8c830004, 0x2c620010,
-0x10400013, 0x3c020001, 0x24630001, 0xac830004,
-0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004,
-0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021,
-0x14440015, 0x24020001, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x1000000f, 0x24020001,
-0x3c020001, 0x344230c8, 0x2e21021, 0x54820004,
-0x24820008, 0x3c020001, 0x34422ec8, 0x2e21021,
-0x402021, 0x24020001, 0xaf4400f4, 0xac890000,
-0xac820004, 0x24020001, 0x3e00008, 0x0,
-0x3e00008, 0x0, 0x8fa90010, 0x8f83010c,
-0x8faa0014, 0x8fab0018, 0x1060000a, 0x276247e0,
-0x14620002, 0x24680020, 0x27684000, 0x8f820108,
-0x11020004, 0x0, 0x8f820104, 0x15020007,
-0x0, 0x8f430338, 0x1021, 0x24630001,
-0xaf430338, 0x10000035, 0x8f430338, 0xac640000,
-0xac650004, 0xac660008, 0xa467000e, 0xac690018,
-0xac6a001c, 0xac6b0010, 0xac620014, 0xaf880100,
-0x8f4400ec, 0x8c820000, 0x30420006, 0x10400019,
-0x31220006, 0x10400018, 0x3c020001, 0x8c830004,
-0x2c620010, 0x10400013, 0x3c020001, 0x24630001,
-0xac830004, 0x8f4300f0, 0x34422ec0, 0x2e21021,
-0x54620004, 0x24620008, 0x3c020001, 0x34422cc0,
-0x2e21021, 0x14440015, 0x24020001, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x1000000f,
-0x24020001, 0x3c020001, 0x34422ec0, 0x2e21021,
-0x54820004, 0x24820008, 0x3c020001, 0x34422cc0,
-0x2e21021, 0x402021, 0x24020001, 0xaf4400ec,
-0xac890000, 0xac820004, 0x24020001, 0x3e00008,
-0x0, 0x3e00008, 0x0, 0x27bdffd8,
-0x3c040001, 0x2484648c, 0x3c050001, 0xafbf0024,
-0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900104,
-0x8f9100b0, 0x8f92011c, 0x34a52500, 0x8f820100,
-0x2403021, 0x2203821, 0xafa20010, 0xc002b3b,
-0xafb00014, 0x8e020008, 0xafa20010, 0x8e02000c,
-0x3c040001, 0x24846498, 0xafa20014, 0x8e060000,
-0x8e070004, 0x3c050001, 0xc002b3b, 0x34a52510,
-0x8e020018, 0xafa20010, 0x8e02001c, 0x3c040001,
-0x248464a4, 0xafa20014, 0x8e060010, 0x8e070014,
-0x3c050001, 0xc002b3b, 0x34a52520, 0x3c027f00,
-0x2221024, 0x3c030800, 0x54430016, 0x3c030200,
-0x8f82009c, 0x3042ffff, 0x14400012, 0x3c030200,
-0x3c040001, 0x248464b0, 0x3c050002, 0x34a5f030,
-0x3021, 0x3821, 0x36420002, 0xaf82011c,
-0x36220001, 0xaf8200b0, 0xaf900104, 0xaf92011c,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x10000024,
-0x0, 0x2c31024, 0x1040000d, 0x2231024,
-0x1040000b, 0x36420002, 0xaf82011c, 0x36220001,
-0xaf8200b0, 0xaf900104, 0xaf92011c, 0x8f420330,
-0x24420001, 0xaf420330, 0x10000015, 0x8f420330,
-0x3c040001, 0x248464b8, 0x240202a9, 0xafa20010,
-0xafa00014, 0x8f860144, 0x3c070001, 0x24e764c0,
-0xc002b3b, 0x3405dead, 0x8f82011c, 0x34420002,
-0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
-0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
-0x8fbf0024, 0x8fb20020, 0x8fb1001c, 0x8fb00018,
-0x3e00008, 0x27bd0028, 0x27bdffd8, 0x3c040001,
-0x248464e8, 0x3c050001, 0xafbf0024, 0xafb20020,
-0xafb1001c, 0xafb00018, 0x8f900124, 0x8f9100a0,
-0x8f92011c, 0x34a52600, 0x8f820120, 0x2403021,
-0x2203821, 0xafa20010, 0xc002b3b, 0xafb00014,
-0x8e020008, 0xafa20010, 0x8e02000c, 0x3c040001,
-0x248464f4, 0xafa20014, 0x8e060000, 0x8e070004,
-0x3c050001, 0xc002b3b, 0x34a52610, 0x8e020018,
-0xafa20010, 0x8e02001c, 0x3c040001, 0x24846500,
-0xafa20014, 0x8e060010, 0x8e070014, 0x3c050001,
-0xc002b3b, 0x34a52620, 0x3c027f00, 0x2221024,
-0x3c030800, 0x54430016, 0x3c030200, 0x8f8200ac,
-0x3042ffff, 0x14400012, 0x3c030200, 0x3c040001,
-0x2484650c, 0x3c050001, 0x34a5f030, 0x3021,
-0x3821, 0x36420002, 0xaf82011c, 0x36220001,
-0xaf8200a0, 0xaf900124, 0xaf92011c, 0xafa00010,
-0xc002b3b, 0xafa00014, 0x10000024, 0x0,
-0x2c31024, 0x1040000d, 0x2231024, 0x1040000b,
-0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0,
-0xaf900124, 0xaf92011c, 0x8f42032c, 0x24420001,
-0xaf42032c, 0x10000015, 0x8f42032c, 0x3c040001,
-0x248464b8, 0x240202e2, 0xafa20010, 0xafa00014,
-0x8f860144, 0x3c070001, 0x24e764c0, 0xc002b3b,
-0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
-0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
-0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024,
-0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
-0x27bd0028, 0x6021, 0x5021, 0x3021,
-0x2821, 0x6821, 0x4821, 0x7821,
-0x7021, 0x8f880124, 0x8f870104, 0x1580002e,
-0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120,
-0x10460029, 0x0, 0x3c040001, 0x8c846ee4,
-0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004,
-0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e,
-0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014,
-0x10000012, 0x24c60020, 0x10400017, 0x0,
-0x3c040001, 0x8c846ee4, 0x8d020000, 0x8d030004,
-0xac820000, 0xac830004, 0x8d020008, 0xac820008,
-0x9502000e, 0xa482000e, 0x8d020010, 0x25060020,
-0xac820010, 0x8d020014, 0x240c0001, 0xc01821,
-0xac820014, 0x27624fe0, 0x43102b, 0x54400001,
-0x27634800, 0x603021, 0x1540002f, 0x31620100,
-0x11200014, 0x31628000, 0x8f820100, 0x1045002a,
-0x31620100, 0x3c040001, 0x8c846ee0, 0x8ca20000,
-0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008,
-0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010,
-0x240a0001, 0xac820010, 0x8ca20014, 0x10000012,
-0x24a50020, 0x10400018, 0x31620100, 0x3c040001,
-0x8c846ee0, 0x8ce20000, 0x8ce30004, 0xac820000,
-0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e,
-0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010,
-0x8ce20014, 0x240a0001, 0xa01821, 0xac820014,
-0x276247e0, 0x43102b, 0x54400001, 0x27634000,
-0x602821, 0x31620100, 0x5440001d, 0x31621000,
-0x11a00009, 0x31a20800, 0x10400004, 0x25020020,
-0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124,
-0x8f880124, 0x6821, 0x11800011, 0x31621000,
-0x3c040001, 0x8c846ee4, 0x8c820000, 0x8c830004,
-0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4,
-0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021,
-0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000,
-0x1440ff82, 0x0, 0x1120000f, 0x31220800,
-0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000,
-0x3c020002, 0x1221024, 0x10400004, 0x24e20020,
-0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104,
-0x8f870104, 0x4821, 0x1140ff70, 0x0,
-0x3c040001, 0x8c846ee0, 0x8c820000, 0x8c830004,
-0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4,
-0x9482000e, 0xaf82009c, 0x8c820010, 0x5021,
-0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014,
-0x3e00008, 0x0, 0x6021, 0x5821,
-0x3021, 0x2821, 0x6821, 0x5021,
-0x7821, 0x7021, 0x8f880124, 0x8f870104,
-0x3c180100, 0x1580002e, 0x8f89011c, 0x11a00014,
-0x31220800, 0x8f820120, 0x10460029, 0x0,
-0x3c040001, 0x8c846ee4, 0x8cc20000, 0x8cc30004,
-0xac820000, 0xac830004, 0x8cc20008, 0xac820008,
-0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001,
-0xac820010, 0x8cc20014, 0x10000012, 0x24c60020,
-0x10400017, 0x0, 0x3c040001, 0x8c846ee4,
-0x8d020000, 0x8d030004, 0xac820000, 0xac830004,
-0x8d020008, 0xac820008, 0x9502000e, 0xa482000e,
-0x8d020010, 0x25060020, 0xac820010, 0x8d020014,
-0x240c0001, 0xc01821, 0xac820014, 0x27624fe0,
-0x43102b, 0x54400001, 0x27634800, 0x603021,
-0x1560002f, 0x31220100, 0x11400014, 0x31228000,
-0x8f820100, 0x1045002a, 0x31220100, 0x3c040001,
-0x8c846ee0, 0x8ca20000, 0x8ca30004, 0xac820000,
-0xac830004, 0x8ca20008, 0xac820008, 0x94a2000e,
-0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010,
-0x8ca20014, 0x10000012, 0x24a50020, 0x10400018,
-0x31220100, 0x3c040001, 0x8c846ee0, 0x8ce20000,
-0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008,
-0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010,
-0x24e50020, 0xac820010, 0x8ce20014, 0x240b0001,
-0xa01821, 0xac820014, 0x276247e0, 0x43102b,
-0x54400001, 0x27634000, 0x602821, 0x31220100,
-0x5440001d, 0x31221000, 0x11a00009, 0x31a20800,
-0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000,
-0x25020020, 0xaf820124, 0x8f880124, 0x6821,
-0x11800011, 0x31221000, 0x3c040001, 0x8c846ee4,
-0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084,
-0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac,
-0x8c820010, 0x6021, 0xaf8200a0, 0x8c8d0010,
-0x8c8f0014, 0x31221000, 0x14400022, 0x0,
-0x1140000f, 0x31420800, 0x10400004, 0x3c020002,
-0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1421024,
-0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4,
-0x24e20020, 0xaf820104, 0x8f870104, 0x5021,
-0x11600010, 0x0, 0x3c040001, 0x8c846ee0,
-0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094,
-0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c,
-0x8c820010, 0x5821, 0xaf8200b0, 0x8c8a0010,
-0x8c8e0014, 0x8f820070, 0x3c031000, 0x431024,
-0x1040ff5c, 0x0, 0x8f820054, 0x24420005,
-0xaf820078, 0x8c040234, 0x10800016, 0x1821,
-0x3c020001, 0x571021, 0x8c4240e8, 0x24420005,
-0x3c010001, 0x370821, 0xac2240e8, 0x3c020001,
-0x571021, 0x8c4240e8, 0x44102b, 0x14400009,
-0x24020001, 0x3c030080, 0x3c010001, 0x370821,
-0xac2040e8, 0x3c010001, 0x370821, 0x1000000c,
-0xa02240f0, 0x3c020001, 0x571021, 0x904240f0,
-0x14400006, 0x3c020080, 0x3c020001, 0x571021,
-0x904240f1, 0x10400002, 0x3c020080, 0x621825,
-0x8c040230, 0x10800013, 0x0, 0x3c020001,
-0x571021, 0x8c4240ec, 0x24420005, 0x3c010001,
-0x370821, 0xac2240ec, 0x3c020001, 0x571021,
-0x8c4240ec, 0x44102b, 0x14400006, 0x0,
-0x3c010001, 0x370821, 0xac2040ec, 0x10000006,
-0x781825, 0x3c020001, 0x571021, 0x904240f2,
-0x54400001, 0x781825, 0x1060ff1a, 0x0,
-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x431025, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x1000ff05,
-0xaf80004c, 0x1000ff03, 0xaf800048, 0x3e00008,
-0x0, 0x0, 0x0, 0x3c020001,
-0x8c426d28, 0x27bdffe8, 0xafbf0014, 0x14400012,
-0xafb00010, 0x3c100001, 0x26106f90, 0x2002021,
-0xc002ba8, 0x24052000, 0x26021fe0, 0x3c010001,
-0xac226eec, 0x3c010001, 0xac226ee8, 0xac020250,
-0x24022000, 0xac100254, 0xac020258, 0x24020001,
-0x3c010001, 0xac226d28, 0x8fbf0014, 0x8fb00010,
-0x3e00008, 0x27bd0018, 0x3c090001, 0x8d296eec,
-0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000,
-0x8c820004, 0xad250008, 0xad220004, 0x8f820054,
-0xad260010, 0xad270014, 0xad230018, 0xad28001c,
-0xad22000c, 0x2529ffe0, 0x3c020001, 0x24426f90,
-0x122102b, 0x10400003, 0x0, 0x3c090001,
-0x8d296ee8, 0x3c020001, 0x8c426d10, 0xad220000,
-0x3c020001, 0x8c426d10, 0x3c010001, 0xac296eec,
-0xad220004, 0xac090250, 0x3e00008, 0x0,
-0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e106eec,
-0x3c020001, 0x8c426d10, 0xafb10014, 0x808821,
-0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018,
-0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c,
-0xae020000, 0x3c020001, 0x8c426d10, 0xc09821,
-0xe0a821, 0x10800006, 0xae020004, 0x26050008,
-0xc002bb3, 0x24060018, 0x10000005, 0x2610ffe0,
-0x26040008, 0xc002ba8, 0x24050018, 0x2610ffe0,
-0x3c030001, 0x24636f90, 0x203102b, 0x10400003,
-0x0, 0x3c100001, 0x8e106ee8, 0x8e220000,
-0xae020000, 0x8e220004, 0xae120008, 0xae020004,
-0x8f820054, 0xae130010, 0xae150014, 0xae1e0018,
-0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0,
-0x203102b, 0x10400003, 0x0, 0x3c100001,
-0x8e106ee8, 0x3c020001, 0x8c426d10, 0xae020000,
-0x3c020001, 0x8c426d10, 0x3c010001, 0xac306eec,
-0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024,
-0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
-0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821,
-0x83102b, 0x10400006, 0x0, 0xac800000,
-0x24840004, 0x83102b, 0x5440fffd, 0xac800000,
-0x3e00008, 0x0, 0xa61821, 0xa3102b,
-0x10400007, 0x0, 0x8c820000, 0xaca20000,
-0x24a50004, 0xa3102b, 0x1440fffb, 0x24840004,
-0x3e00008, 0x0, 0x861821, 0x83102b,
-0x10400007, 0x0, 0x8ca20000, 0xac820000,
-0x24840004, 0x83102b, 0x1440fffb, 0x24a50004,
-0x3e00008, 0x0, 0x63080, 0x861821,
-0x83102b, 0x10400006, 0x0, 0xac850000,
-0x24840004, 0x83102b, 0x5440fffd, 0xac850000,
-0x3e00008, 0x0, 0x0, 0x26e50028,
-0xa03021, 0x274301c0, 0x8f4d0358, 0x8f47035c,
-0x8f480360, 0x8f490364, 0x8f4a0368, 0x8f4b0204,
-0x8f4c0200, 0x24640400, 0x64102b, 0x10400008,
-0x3c0208ff, 0x8cc20000, 0xac620000, 0x24630004,
-0x64102b, 0x1440fffb, 0x24c60004, 0x3c0208ff,
-0x3442ffff, 0x3c03c0ff, 0xaf4d0358, 0xaf47035c,
-0xaf480360, 0xaf490364, 0xaf4a0368, 0xaf4b0204,
-0xaf4c0200, 0x8f840220, 0x3463ffff, 0x8f860200,
-0x821024, 0x34420004, 0xc31824, 0x34630004,
-0xaf820220, 0xaf830200, 0x8ca20214, 0xac020084,
-0x8ca20218, 0xac020088, 0x8ca2021c, 0xac02008c,
-0x8ca20220, 0xac020090, 0x8ca20224, 0xac020094,
-0x8ca20228, 0xac020098, 0x8ca2022c, 0xac02009c,
-0x8ca20230, 0xac0200a0, 0x8ca20234, 0xac0200a4,
-0x8ca20238, 0xac0200a8, 0x8ca2023c, 0xac0200ac,
-0x8ca20240, 0xac0200b0, 0x8ca20244, 0xac0200b4,
-0x8ca20248, 0xac0200b8, 0x8ca2024c, 0xac0200bc,
-0x8ca2001c, 0xac020080, 0x8ca20018, 0xac0200c0,
-0x8ca20020, 0xac0200cc, 0x8ca20024, 0xac0200d0,
-0x8ca201d0, 0xac0200e0, 0x8ca201d4, 0xac0200e4,
-0x8ca201d8, 0xac0200e8, 0x8ca201dc, 0xac0200ec,
-0x8ca201e0, 0xac0200f0, 0x8ca20098, 0x8ca3009c,
-0xac0300fc, 0x8ca200a8, 0x8ca300ac, 0xac0300f4,
-0x8ca200a0, 0x8ca300a4, 0x30840004, 0xac0300f8,
-0x14800007, 0x30c20004, 0x8f820220, 0x3c0308ff,
-0x3463fffb, 0x431024, 0xaf820220, 0x30c20004,
-0x14400006, 0x0, 0x8f820200, 0x3c03c0ff,
-0x3463fffb, 0x431024, 0xaf820200, 0x8f4202dc,
-0xa34005c5, 0x24420001, 0xaf4202dc, 0x8f4202dc,
-0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
-0xafb00020, 0x8f430024, 0x8f420020, 0x10620038,
-0x0, 0x8f430020, 0x8f420024, 0x622023,
-0x4810003, 0x0, 0x8f420040, 0x822021,
-0x8f430030, 0x8f420024, 0x43102b, 0x14400005,
-0x0, 0x8f430040, 0x8f420024, 0x10000005,
-0x621023, 0x8f420030, 0x8f430024, 0x431023,
-0x2442ffff, 0x406021, 0x8c102a, 0x54400001,
-0x806021, 0x8f4a0024, 0x8f490040, 0x8f480024,
-0x8f440180, 0x8f450184, 0x8f460024, 0x8f4b001c,
-0x24070001, 0xafa70010, 0x84100, 0x1001821,
-0x14c5021, 0x2529ffff, 0x1498024, 0xafb00014,
-0x8f470014, 0x1021, 0x63100, 0xafa70018,
-0xa32821, 0xa3382b, 0x822021, 0x872021,
-0x8f420108, 0x1663021, 0x40f809, 0xc3900,
-0x54400001, 0xaf500024, 0x8f430024, 0x8f420020,
-0x14620018, 0x0, 0x8f420000, 0x10400007,
-0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
-0x0, 0x10000005, 0x0, 0xaf800048,
-0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
-0x2403ffef, 0x431024, 0xaf820060, 0x8f420000,
-0x10400003, 0x0, 0x10000002, 0xaf80004c,
-0xaf800048, 0x8fbf0024, 0x8fb00020, 0x3e00008,
-0x27bd0028, 0x3e00008, 0x0, 0x27bdffc0,
-0x32c20020, 0xafbf0038, 0xafb30034, 0xafb20030,
-0xafb1002c, 0x10400004, 0xafb00028, 0x8f530028,
-0x10000002, 0x0, 0x8f530020, 0x8f420030,
-0x105300eb, 0x21100, 0x8f43001c, 0x628021,
-0x8e040000, 0x8e050004, 0x96120008, 0x8f420090,
-0x9611000a, 0x3246ffff, 0x46102a, 0x10400017,
-0x0, 0x8f8200d8, 0x8f430098, 0x431023,
-0x2442dcbe, 0xaf420090, 0x8f420090, 0x2842dcbf,
-0x10400005, 0x0, 0x8f420090, 0x8f430144,
-0x431021, 0xaf420090, 0x8f420090, 0x46102a,
-0x10400006, 0x0, 0x8f420348, 0x24420001,
-0xaf420348, 0x100000e1, 0x8f420348, 0x8f8200fc,
-0x14400006, 0x0, 0x8f420344, 0x24420001,
-0xaf420344, 0x100000d9, 0x8f420344, 0x934205c2,
-0x1040000b, 0x32c20008, 0x10400008, 0x32220200,
-0x10400006, 0x3c034000, 0x9602000e, 0xaf4300ac,
-0x21400, 0x10000002, 0xaf4200b0, 0xaf4000ac,
-0x32220004, 0x1040007f, 0x32220800, 0x10400003,
-0x3247ffff, 0x10000002, 0x24020020, 0x24020004,
-0xafa20010, 0x8f420030, 0xafa20014, 0x8f420010,
-0x3c030002, 0x431025, 0xafa20018, 0x8f460098,
-0x8f420108, 0x40f809, 0x0, 0x104000b7,
-0x0, 0x8f42009c, 0x8f430094, 0x2421021,
-0xaf42009c, 0xae03000c, 0x8f4200ac, 0x10400008,
-0x3c034000, 0x8f420094, 0x431025, 0xafa20020,
-0x8f42009c, 0x8f4300b0, 0x10000004, 0x431025,
-0x8f420094, 0xafa20020, 0x8f42009c, 0xafa20024,
-0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000,
-0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c,
-0x8f440270, 0x8f450274, 0x401821, 0x1021,
-0xa32821, 0xa3302b, 0x822021, 0x862021,
-0x32230060, 0x24020040, 0xaf440270, 0xaf450274,
-0x10620017, 0x2c620041, 0x10400005, 0x24020020,
-0x10620008, 0x24020001, 0x10000026, 0x0,
-0x24020060, 0x10620019, 0x24020001, 0x10000021,
-0x0, 0x8f420278, 0x8f43027c, 0x24630001,
-0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
-0x8f420278, 0x8f43027c, 0x10000016, 0x24020001,
-0x8f420280, 0x8f430284, 0x24630001, 0x2c640001,
-0x441021, 0xaf420280, 0xaf430284, 0x8f420280,
-0x8f430284, 0x1000000b, 0x24020001, 0x8f420288,
-0x8f43028c, 0x24630001, 0x2c640001, 0x441021,
-0xaf420288, 0xaf43028c, 0x8f420288, 0x8f43028c,
-0x24020001, 0xa34205c2, 0x8f420098, 0x3244ffff,
-0x2406fff8, 0x8f45013c, 0x441021, 0x24420007,
-0x461024, 0x24840007, 0xaf420094, 0x8f420090,
-0x8f430094, 0x862024, 0x441023, 0x65182b,
-0x14600005, 0xaf420090, 0x8f420094, 0x8f430144,
-0x431023, 0xaf420094, 0x8f420094, 0x10000023,
-0xaf40009c, 0x3247ffff, 0x50e00022, 0x32c20020,
-0x14400002, 0x24020010, 0x24020002, 0xafa20010,
-0x8f420030, 0xafa20014, 0x8f420010, 0xafa20018,
-0x8f460098, 0x8f420108, 0x40f809, 0x0,
-0x1040003a, 0x3245ffff, 0x8f420098, 0x8f430090,
-0x8f46013c, 0x451021, 0xaf420098, 0x8f42009c,
-0x8f440098, 0xa34005c2, 0x651823, 0xaf430090,
-0x451021, 0x86202b, 0x14800005, 0xaf42009c,
-0x8f420098, 0x8f430144, 0x431023, 0xaf420098,
-0x32c20020, 0x10400005, 0x0, 0x8f420358,
-0x2442ffff, 0xaf420358, 0x8f420358, 0x8f420030,
-0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
-0xaf420030, 0x8f420030, 0x14530018, 0x0,
-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x2403fff7, 0x431024,
-0xaf820060, 0x8f420000, 0x10400003, 0x0,
-0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0038,
-0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028,
-0x3e00008, 0x27bd0040, 0x3e00008, 0x0,
-0x27bdffd0, 0x32c20020, 0xafbf002c, 0xafb20028,
-0xafb10024, 0x10400004, 0xafb00020, 0x8f520028,
-0x10000002, 0x0, 0x8f520020, 0x8f420030,
-0x105200b5, 0x21100, 0x8f43001c, 0x628021,
-0x8e040000, 0x8e050004, 0x96110008, 0x8f420090,
-0x9607000a, 0x3226ffff, 0x46102a, 0x10400017,
-0x0, 0x8f8200d8, 0x8f430098, 0x431023,
-0x2442dc46, 0xaf420090, 0x8f420090, 0x2842dc47,
-0x10400005, 0x0, 0x8f420090, 0x8f430144,
-0x431021, 0xaf420090, 0x8f420090, 0x46102a,
-0x10400006, 0x0, 0x8f420348, 0x24420001,
-0xaf420348, 0x100000ab, 0x8f420348, 0x8f8600fc,
-0x10c0000c, 0x0, 0x8f8200f4, 0x2403fff8,
-0x431024, 0x461023, 0x218c3, 0x58600001,
-0x24630100, 0x8f42008c, 0x43102b, 0x14400006,
-0x712c2, 0x8f420344, 0x24420001, 0xaf420344,
-0x10000098, 0x8f420344, 0x934305c2, 0x1060000f,
-0x30460001, 0x8f420010, 0x34480400, 0x32c20008,
-0x10400008, 0x30e20200, 0x10400006, 0x3c034000,
-0x9602000e, 0xaf4300ac, 0x21400, 0x10000004,
-0xaf4200b0, 0x10000002, 0xaf4000ac, 0x8f480010,
-0x30e20004, 0x10400045, 0x3227ffff, 0x8f4900ac,
-0x11200005, 0x30c200ff, 0x14400006, 0x24020040,
-0x10000004, 0x24020008, 0x14400002, 0x24020020,
-0x24020004, 0xafa20010, 0x8f430030, 0x11200004,
-0xafa30014, 0x8f4200b0, 0x621025, 0xafa20014,
-0x3c020002, 0x1021025, 0xafa20018, 0x8f460098,
-0x8f420108, 0x40f809, 0x0, 0x10400069,
-0x3224ffff, 0x8f42008c, 0x8f430094, 0x24420001,
-0xaf42008c, 0x24020001, 0xae03000c, 0xa34205c2,
-0x8f420098, 0x2406fff8, 0x8f45013c, 0x441021,
-0x24420007, 0x461024, 0x24840007, 0xaf420094,
-0x8f420090, 0x8f430094, 0x862024, 0x441023,
-0x65182b, 0x14600005, 0xaf420090, 0x8f420094,
-0x8f430144, 0x431023, 0xaf420094, 0x8f430094,
-0x8f420140, 0x43102b, 0x10400009, 0x0,
-0x8f43013c, 0x8f440094, 0x8f420090, 0x8f450138,
-0x641823, 0x431023, 0xaf420090, 0xaf450094,
-0x8f420094, 0x1000001f, 0xaf420098, 0x10e0001d,
-0x30c200ff, 0x14400002, 0x24020010, 0x24020002,
-0xafa20010, 0x8f420030, 0xafa80018, 0xafa20014,
-0x8f460098, 0x8f420108, 0x40f809, 0x0,
-0x10400030, 0x3225ffff, 0x8f420098, 0x8f44013c,
-0x451021, 0xaf420098, 0x8f420090, 0x8f430098,
-0xa34005c2, 0x451023, 0x64182b, 0x14600005,
-0xaf420090, 0x8f420098, 0x8f430144, 0x431023,
-0xaf420098, 0x8f420030, 0x8f430040, 0x24420001,
-0x2463ffff, 0x431024, 0xaf420030, 0x8f420030,
-0x14520018, 0x0, 0x8f420000, 0x10400007,
-0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
-0x0, 0x10000005, 0x0, 0xaf800048,
-0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
-0x2403fff7, 0x431024, 0xaf820060, 0x8f420000,
-0x10400003, 0x0, 0x10000002, 0xaf80004c,
-0xaf800048, 0x8fbf002c, 0x8fb20028, 0x8fb10024,
-0x8fb00020, 0x3e00008, 0x27bd0030, 0x3e00008,
-0x0, 0x27bdffd8, 0x3c020001, 0x34422ec0,
-0xafbf0020, 0x8f4300f0, 0x8f840108, 0x2e21021,
-0x54620004, 0x24620008, 0x3c020001, 0x34422cc0,
-0x2e21021, 0x401821, 0xaf4300f0, 0xac600000,
-0x8f4200ec, 0x8c660004, 0x14620004, 0x3c020001,
-0x24820020, 0x1000000f, 0xaf820108, 0x8f4300f0,
-0x34422ec0, 0x2e21021, 0x54620004, 0x24620008,
-0x3c020001, 0x34422cc0, 0x2e21021, 0x401821,
-0x8c620004, 0x21140, 0x821021, 0xaf820108,
-0xac600000, 0x8c850018, 0x30a20036, 0x1040006c,
-0x30a20001, 0x8c82001c, 0x8f430040, 0x8f440034,
-0x24420001, 0x2463ffff, 0x431024, 0x862021,
-0xaf42002c, 0x30a20030, 0x14400006, 0xaf440034,
-0x8f420034, 0x8c03023c, 0x43102b, 0x144000b4,
-0x0, 0x32c20010, 0x10400028, 0x24070008,
-0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
-0x8f860120, 0x24020080, 0xafa20010, 0xafa30014,
-0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x14400011, 0x24020001, 0x3c010001, 0x370821,
-0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128,
-0x3c040001, 0x248467c4, 0xafa20014, 0x8f46002c,
-0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51100,
-0x10000036, 0x0, 0x8f420300, 0x8f43002c,
-0x24420001, 0xaf420300, 0x8f420300, 0x24020001,
-0xa34205c1, 0x10000026, 0xaf430038, 0x8f440170,
-0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
-0x24020020, 0xafa20010, 0xafa30014, 0xafa80018,
-0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
-0x24020001, 0x3c010001, 0x370821, 0xa02240f0,
-0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
-0x248467b8, 0xafa20014, 0x8f46002c, 0x8f870120,
-0x3c050009, 0xc002b3b, 0x34a50900, 0x1000000f,
-0x0, 0x8f420300, 0x24420001, 0xaf420300,
-0x8f420300, 0x8f42002c, 0xa34005c1, 0xaf420038,
-0x3c010001, 0x370821, 0xa02040f1, 0x3c010001,
-0x370821, 0xa02040f0, 0xaf400034, 0x8f420314,
-0x24420001, 0xaf420314, 0x10000059, 0x8f420314,
-0x10400022, 0x30a27000, 0x8c85001c, 0x8f420028,
-0xa22023, 0x4810003, 0x0, 0x8f420040,
-0x822021, 0x8f420358, 0x8f430000, 0xaf450028,
-0x441021, 0x10600007, 0xaf420358, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x34420008, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x10000038,
-0xaf80004c, 0x10000036, 0xaf800048, 0x1040002f,
-0x30a21000, 0x1040000c, 0x30a24000, 0x8c83001c,
-0x8f420050, 0x622023, 0x4820001, 0x24840200,
-0x8f42035c, 0x441021, 0xaf42035c, 0x8f420368,
-0x1000001a, 0xaf430050, 0x1040000c, 0x32c28000,
-0x8c83001c, 0x8f420070, 0x622023, 0x4820001,
-0x24840400, 0x8f420364, 0x441021, 0xaf420364,
-0x8f420368, 0x1000000d, 0xaf430070, 0x1040000e,
-0x3c020800, 0x8c83001c, 0x8f420060, 0x622023,
-0x4820001, 0x24840100, 0x8f420360, 0x441021,
-0xaf420360, 0x8f420368, 0xaf430060, 0x441021,
-0xaf420368, 0x3c020800, 0x2c21024, 0x50400008,
-0x36940040, 0x10000006, 0x0, 0x30a20100,
-0x10400003, 0x0, 0xc002bd8, 0x0,
-0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008,
-0x0, 0x27bdffa8, 0xafbf0050, 0xafbe004c,
-0xafb50048, 0xafb30044, 0xafb20040, 0xafb1003c,
-0xafb00038, 0x8f910108, 0x26220020, 0xaf820108,
-0x8e320018, 0xa821, 0x32420024, 0x104001ba,
-0xf021, 0x8e26001c, 0x8f43001c, 0x61100,
-0x621821, 0x8c70000c, 0x9604000c, 0x962d0016,
-0x9473000a, 0x2c8305dd, 0x38828870, 0x2c420001,
-0x621825, 0x10600015, 0x2821, 0x32c20040,
-0x10400015, 0x24020800, 0x96030014, 0x14620012,
-0x3402aaaa, 0x9603000e, 0x14620007, 0x2021,
-0x96030010, 0x24020300, 0x14620004, 0x801021,
-0x96020012, 0x2c440001, 0x801021, 0x54400006,
-0x24050016, 0x10000004, 0x0, 0x24020800,
-0x50820001, 0x2405000e, 0x934205c3, 0x14400008,
-0x5821, 0x240b0001, 0x32620180, 0xaf4500a8,
-0xaf5000a0, 0x10400002, 0xaf4600a4, 0xa34b05c3,
-0x10a00085, 0x2054021, 0x91020000, 0x3821,
-0x3042000f, 0x25080, 0x32c20002, 0x10400012,
-0x10a1821, 0x32620002, 0x10400010, 0x32c20001,
-0x1002021, 0x94820000, 0x24840002, 0xe23821,
-0x83102b, 0x1440fffb, 0x30e2ffff, 0x71c02,
-0x623821, 0x71c02, 0x30e2ffff, 0x623821,
-0x71027, 0xa502000a, 0x32c20001, 0x1040006a,
-0x32620001, 0x10400068, 0x0, 0x8f4200a8,
-0x10400065, 0x0, 0x8f4200a0, 0x8f4300a8,
-0x431021, 0x904c0009, 0x318900ff, 0x39230006,
-0x3182b, 0x39220011, 0x2102b, 0x621824,
-0x1060000c, 0x3c050006, 0x8f4200a4, 0x3c040001,
-0x248467d4, 0xafa20010, 0x8f4200a0, 0x34a54600,
-0x1203821, 0xc002b3b, 0xafa20014, 0x1000004e,
-0x0, 0x32c20004, 0x14400013, 0x2821,
-0x316200ff, 0x14400004, 0x0, 0x95020002,
-0x1000000d, 0x4a2823, 0x9505000c, 0x9502000e,
-0x95030010, 0xa22821, 0xa32821, 0x95030012,
-0x91040009, 0x95020002, 0xa32821, 0xa42821,
-0x4a1023, 0xa22821, 0x2002021, 0x94820000,
-0x24840002, 0xe23821, 0x88102b, 0x1440fffb,
-0x71c02, 0x30e2ffff, 0x623821, 0x71c02,
-0x30e2ffff, 0x623821, 0x1a52821, 0x51c02,
-0x30a2ffff, 0x622821, 0x51c02, 0x30a2ffff,
-0x622821, 0xa72823, 0x51402, 0xa22821,
-0x30a5ffff, 0x50a00001, 0x3405ffff, 0x316200ff,
-0x14400008, 0x318300ff, 0x8f4300a0, 0x8f4200a8,
-0x624021, 0x91020000, 0x3042000f, 0x25080,
-0x318300ff, 0x24020006, 0x14620003, 0x10a1021,
-0x10000002, 0x24440010, 0x24440006, 0x316200ff,
-0x14400006, 0x0, 0x94820000, 0xa22821,
-0x51c02, 0x30a2ffff, 0x622821, 0x934205c3,
-0x10400003, 0x32620100, 0x50400003, 0xa4850000,
-0x52827, 0xa4850000, 0x9622000e, 0x8f43009c,
-0x621821, 0x32a200ff, 0x10400007, 0xaf43009c,
-0x3c024000, 0x2021025, 0xafa20020, 0x8f42009c,
-0x10000003, 0x5e1025, 0xafb00020, 0x8f42009c,
-0xafa20024, 0x32620080, 0x10400010, 0x32620100,
-0x8f4200b4, 0x24430001, 0x210c0, 0x571021,
-0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001,
-0x220821, 0xac2338e8, 0x3c010001, 0x220821,
-0xac2438ec, 0x100000a5, 0x32c20020, 0x10400064,
-0x0, 0x8f4200b4, 0x24430001, 0x210c0,
-0x571021, 0xaf4300b4, 0x8fa30020, 0x8fa40024,
-0x3c010001, 0x220821, 0xac2338e8, 0x3c010001,
-0x220821, 0xac2438ec, 0x8f4200b4, 0x10400051,
-0x3821, 0x3c090001, 0x352938e8, 0x3c08001f,
-0x3508ffff, 0x240bffff, 0x340affff, 0x710c0,
-0x571021, 0x491021, 0x8c430000, 0x8c440004,
-0xafa30028, 0xafa4002c, 0x8f8200fc, 0x8fa30028,
-0x8fa4002c, 0xac430000, 0xac440004, 0x24420008,
-0xaf8200f0, 0x8f42008c, 0x2442ffff, 0xaf42008c,
-0x97a2002e, 0x8f440270, 0x8f450274, 0x401821,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaf440270, 0xaf450274, 0x8fa20028,
-0x481024, 0x90430000, 0x30630001, 0x1460000b,
-0x402021, 0x8f420278, 0x8f43027c, 0x24630001,
-0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
-0x8f420278, 0x1000001a, 0x8f43027c, 0x8c820000,
-0x144b000e, 0x0, 0x94820004, 0x144a000b,
-0x0, 0x8f420288, 0x8f43028c, 0x24630001,
-0x2c640001, 0x441021, 0xaf420288, 0xaf43028c,
-0x8f420288, 0x1000000a, 0x8f43028c, 0x8f420280,
-0x8f430284, 0x24630001, 0x2c640001, 0x441021,
-0xaf420280, 0xaf430284, 0x8f420280, 0x8f430284,
-0x8f4200b4, 0x24e70001, 0xe2102b, 0x1440ffb8,
-0x710c0, 0xa34005c3, 0x1000003f, 0xaf4000b4,
-0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000,
-0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c,
-0x8f46008c, 0x8f440270, 0x8f450274, 0x401821,
-0x1021, 0x24c6ffff, 0xaf46008c, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0xaf440270,
-0xaf450274, 0x92020000, 0x30420001, 0x1440000c,
-0x2402ffff, 0x8f420278, 0x8f43027c, 0x24630001,
-0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
-0x8f420278, 0x8f43027c, 0x1000001c, 0x32c20020,
-0x8e030000, 0x1462000f, 0x3402ffff, 0x96030004,
-0x1462000c, 0x0, 0x8f420288, 0x8f43028c,
-0x24630001, 0x2c640001, 0x441021, 0xaf420288,
-0xaf43028c, 0x8f420288, 0x8f43028c, 0x1000000b,
-0x32c20020, 0x8f420280, 0x8f430284, 0x24630001,
-0x2c640001, 0x441021, 0xaf420280, 0xaf430284,
-0x8f420280, 0x8f430284, 0x32c20020, 0x10400005,
-0xaf40009c, 0x8f420358, 0x2442ffff, 0xaf420358,
-0x8f420358, 0x8e22001c, 0x8f430040, 0x24420001,
-0x2463ffff, 0x431024, 0xaf42002c, 0x32420060,
-0x14400008, 0x32c20010, 0x8f420034, 0x24420001,
-0xaf420034, 0x8c03023c, 0x43102b, 0x14400102,
-0x32c20010, 0x10400018, 0x24070008, 0x8f440170,
-0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
-0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
-0x8f42010c, 0x40f809, 0x24c6001c, 0x10400047,
-0x24020001, 0x8f420300, 0x8f43002c, 0x24420001,
-0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1,
-0x1000007c, 0xaf430038, 0x8f440170, 0x8f450174,
-0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020020,
-0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
-0x40f809, 0x24c6001c, 0x10400057, 0x24020001,
-0x10000065, 0x0, 0x32420012, 0x10400075,
-0x32420001, 0x9622000e, 0x8f43009c, 0x621821,
-0x32c20020, 0x10400005, 0xaf43009c, 0x8f420358,
-0x2442ffff, 0xaf420358, 0x8f420358, 0x8e22001c,
-0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
-0xaf42002c, 0x32420010, 0x14400008, 0x32c20010,
-0x8f420034, 0x24420001, 0xaf420034, 0x8c03023c,
-0x43102b, 0x144000bc, 0x32c20010, 0x10400028,
-0x24070008, 0x8f440170, 0x8f450174, 0x8f43002c,
-0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010,
-0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
-0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
-0x370821, 0xa02240f1, 0x8f820124, 0xafa20010,
-0x8f820128, 0x3c040001, 0x248467c4, 0xafa20014,
-0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b,
-0x34a51100, 0x10000036, 0x0, 0x8f420300,
-0x8f43002c, 0x24420001, 0xaf420300, 0x8f420300,
-0x24020001, 0xa34205c1, 0x10000026, 0xaf430038,
-0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
-0x8f860120, 0x24020020, 0xafa20010, 0xafa30014,
-0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x14400011, 0x24020001, 0x3c010001, 0x370821,
-0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128,
-0x3c040001, 0x248467b8, 0xafa20014, 0x8f46002c,
-0x8f870120, 0x3c050009, 0xc002b3b, 0x34a50900,
-0x1000000f, 0x0, 0x8f420300, 0x24420001,
-0xaf420300, 0x8f420300, 0x8f42002c, 0xa34005c1,
-0xaf420038, 0x3c010001, 0x370821, 0xa02040f1,
-0x3c010001, 0x370821, 0xa02040f0, 0xaf400034,
-0x8f420314, 0x24420001, 0xaf420314, 0x10000062,
-0x8f420314, 0x10400022, 0x32427000, 0x8e25001c,
-0x8f420028, 0xa22023, 0x4810003, 0x0,
-0x8f420040, 0x822021, 0x8f420358, 0x8f430000,
-0xaf450028, 0x441021, 0x10600007, 0xaf420358,
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
-0x10000005, 0x0, 0xaf800048, 0x8f820048,
-0x1040fffd, 0x0, 0x8f820060, 0x34420008,
-0xaf820060, 0x8f420000, 0x10400003, 0x0,
-0x10000041, 0xaf80004c, 0x1000003f, 0xaf800048,
-0x1040002f, 0x32421000, 0x1040000c, 0x32424000,
-0x8e23001c, 0x8f420050, 0x622023, 0x4820001,
-0x24840200, 0x8f42035c, 0x441021, 0xaf42035c,
-0x8f420368, 0x1000001a, 0xaf430050, 0x1040000c,
-0x32c28000, 0x8e23001c, 0x8f420070, 0x622023,
-0x4820001, 0x24840400, 0x8f420364, 0x441021,
-0xaf420364, 0x8f420368, 0x1000000d, 0xaf430070,
-0x1040000e, 0x3c020800, 0x8e23001c, 0x8f420060,
-0x622023, 0x4820001, 0x24840100, 0x8f420360,
-0x441021, 0xaf420360, 0x8f420368, 0xaf430060,
-0x441021, 0xaf420368, 0x3c020800, 0x2c21024,
-0x50400011, 0x36940040, 0x1000000f, 0x0,
-0x32420048, 0x10400007, 0x24150001, 0x8e22001c,
-0x3c03ffff, 0x43f024, 0x3042ffff, 0x1000fd75,
-0xae22001c, 0x32420100, 0x10400003, 0x0,
-0xc002bd8, 0x0, 0x8fbf0050, 0x8fbe004c,
-0x8fb50048, 0x8fb30044, 0x8fb20040, 0x8fb1003c,
-0x8fb00038, 0x3e00008, 0x27bd0058, 0x3e00008,
-0x0, 0x0, 0x0, 0x8f8300e4,
-0x8f8200e0, 0x2404fff8, 0x441024, 0x621026,
-0x2102b, 0x21023, 0x3e00008, 0x621024,
-0x3e00008, 0x0, 0x27bdffe0, 0xafbf001c,
-0xafb00018, 0x8f8600c4, 0x8f8400e0, 0x8f8500e4,
-0x2402fff8, 0x821824, 0x10a30009, 0x27623ff8,
-0x14a20002, 0x24a20008, 0x27623000, 0x408021,
-0x16030005, 0x30820004, 0x10400004, 0xc02021,
-0x10000022, 0x1021, 0x8e040000, 0x8f42011c,
-0x14a20003, 0x0, 0x8f420120, 0xaf420114,
-0x8ca30000, 0x8f420148, 0x831823, 0x43102b,
-0x10400003, 0x0, 0x8f420148, 0x621821,
-0x94a20006, 0x24420050, 0x62102b, 0x1440000f,
-0xa01021, 0xafa40010, 0xafa30014, 0x8ca60000,
-0x8ca70004, 0x3c040001, 0xc002b3b, 0x24846894,
-0x8f42020c, 0x24420001, 0xaf42020c, 0x8f42020c,
-0x1021, 0xaf9000e8, 0xaf9000e4, 0x8fbf001c,
-0x8fb00018, 0x3e00008, 0x27bd0020, 0x3e00008,
-0x0, 0x8f8400e0, 0x8f8800c4, 0x8f8300e8,
-0x2402fff8, 0x823824, 0xe32023, 0x2c821000,
-0x50400001, 0x24841000, 0x420c2, 0x801821,
-0x8f440258, 0x8f45025c, 0x1021, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0xaf440258,
-0xaf45025c, 0x8f8300c8, 0x8f420148, 0x1032023,
-0x82102b, 0x14400004, 0x801821, 0x8f420148,
-0x822021, 0x801821, 0x8f440250, 0x8f450254,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaf440250, 0xaf450254, 0xaf8800c8,
-0xaf8700e4, 0xaf8700e8, 0x3e00008, 0x0,
-0x27bdff30, 0x240a0001, 0xafbf00c8, 0xafbe00c4,
-0xafb500c0, 0xafb300bc, 0xafb200b8, 0xafb100b4,
-0xafb000b0, 0xa3a00097, 0xafa00044, 0xafaa005c,
-0x934205c4, 0xa7a0008e, 0x1040000a, 0xa7a00086,
-0x8f4b00c4, 0xafab0064, 0x8f4a00c0, 0xafaa006c,
-0x8f4b00cc, 0xafab0074, 0x8f4a00c8, 0x10000129,
-0xafaa007c, 0x8f420114, 0x40f809, 0x0,
-0x403021, 0x10c0034f, 0x0, 0x8cc20000,
-0x8cc30004, 0xafa20020, 0xafa30024, 0x8fab0024,
-0x8faa0020, 0x3162ffff, 0x2442fffc, 0xafa2006c,
-0x3c020006, 0x2c21024, 0xafab007c, 0x14400015,
-0xafaa0064, 0x91420000, 0x30420001, 0x10400011,
-0x2402ffff, 0x8d430000, 0x14620004, 0x3402ffff,
-0x95430004, 0x1062000b, 0x0, 0xc0024bb,
-0x8fa40064, 0x304200ff, 0x14400006, 0x0,
-0x8f420118, 0x40f809, 0x0, 0x1000032d,
-0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff,
-0x431024, 0x3c03ffff, 0x431824, 0x14600003,
-0xafa20024, 0x10000040, 0x1821, 0x3c020080,
-0x621024, 0x10400007, 0x0, 0x8f42038c,
-0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036,
-0x24030001, 0x8f420210, 0x24420001, 0xaf420210,
-0x8f420210, 0x3c020001, 0x621024, 0x10400006,
-0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4,
-0x8f4201c4, 0x3c020002, 0x621024, 0x10400006,
-0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c,
-0x8f42037c, 0x3c020004, 0x621024, 0x10400006,
-0x3c020008, 0x8f420380, 0x24420001, 0xaf420380,
-0x8f420380, 0x3c020008, 0x621024, 0x10400006,
-0x3c020010, 0x8f420384, 0x24420001, 0xaf420384,
-0x8f420384, 0x3c020010, 0x621024, 0x10400006,
-0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0,
-0x8f4201c0, 0x3c020020, 0x621024, 0x10400006,
-0x24030001, 0x8f420388, 0x24420001, 0xaf420388,
-0x8f420388, 0x24030001, 0x8c020260, 0x8fab006c,
-0x4b102b, 0x10400014, 0x307000ff, 0x8f4201e8,
-0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8faa007c,
-0x8f8200e0, 0x354a0100, 0xafaa007c, 0xafa20010,
-0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0,
-0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007,
-0xc002b3b, 0x34a50800, 0x12000010, 0x3c020080,
-0x2c21024, 0x1440000e, 0x32c20400, 0x8fab007c,
-0x3c020080, 0x34420100, 0x1621024, 0x10400005,
-0x0, 0x8f42020c, 0x24420001, 0xaf42020c,
-0x8f42020c, 0x100002b0, 0x8fa3006c, 0x32c20400,
-0x10400015, 0x34028100, 0x8faa0064, 0x9543000c,
-0x14620012, 0x3c020100, 0x240b0200, 0xa7ab008e,
-0x9542000e, 0x8d430008, 0x8d440004, 0x8d450000,
-0x8faa006c, 0x8fab0064, 0x254afffc, 0xafaa006c,
-0xa7a20086, 0xad63000c, 0xad640008, 0xad650004,
-0x256b0004, 0xafab0064, 0x3c020100, 0x2c21024,
-0x10400004, 0x0, 0x8faa006c, 0x254a0004,
-0xafaa006c, 0x8f4200bc, 0x5040000a, 0xafa00074,
-0x8fab006c, 0x4b102b, 0x50400006, 0xafa00074,
-0x8f4200bc, 0x1621023, 0xafa20074, 0x8f4a00bc,
-0xafaa006c, 0x8f420080, 0x8fab006c, 0x4b102b,
-0x10400056, 0x32c28000, 0x1040005e, 0x240a0003,
-0x32c21000, 0x1040005b, 0xafaa005c, 0x10000058,
-0x240b0004, 0x8f420350, 0x2403ffbf, 0x283a024,
-0x24420001, 0xaf420350, 0x1000024f, 0x8f420350,
-0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128,
-0x3c040001, 0x248468d0, 0x26620001, 0xafa20014,
-0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007,
-0xc002b3b, 0x34a52250, 0x1000023f, 0x0,
-0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128,
-0x3c040001, 0x248468d0, 0x24020002, 0xafa20014,
-0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007,
-0xc002b3b, 0x34a52450, 0x1000022f, 0x0,
-0x8ea20000, 0x8ea30004, 0x3c040001, 0x248468e8,
-0xafb00010, 0xafbe0014, 0x8ea70018, 0x34a52800,
-0xc002b3b, 0x603021, 0x10000223, 0x0,
-0xa6b1000a, 0x8f820124, 0x3c040001, 0x248468f0,
-0xafbe0014, 0xafa20010, 0x8f460044, 0x8f870120,
-0x3c050007, 0xc002b3b, 0x34a53000, 0x10000216,
-0x0, 0xa6b1000a, 0xa6b2000e, 0x8f820124,
-0x3c040001, 0x248468fc, 0xafbe0014, 0xafa20010,
-0x8f460044, 0x8f870120, 0x3c050007, 0xc002b3b,
-0x34a53200, 0x10000208, 0x0, 0x8f420084,
-0x8faa006c, 0x4a102b, 0x14400007, 0x3c020001,
-0x2c21024, 0x10400004, 0x0, 0x240b0002,
-0xafab005c, 0x8faa006c, 0x1140021b, 0x27ab0020,
-0xafab00a4, 0x3c0a001f, 0x354affff, 0xafaa009c,
-0x8fab005c, 0x240a0001, 0x556a0021, 0x240a0002,
-0x8f430054, 0x8f420050, 0x1062000b, 0x274b0054,
-0x8f5e0054, 0x3403ecc0, 0xafab004c, 0x27c20001,
-0x304201ff, 0xafa20054, 0x1e1140, 0x431021,
-0x1000006b, 0x2e2a821, 0x8f420044, 0x8faa006c,
-0x3c040001, 0x248468ac, 0xafaa0014, 0xafa20010,
-0x8f460054, 0x8f470050, 0x3c050007, 0xc002b3b,
-0x34a51300, 0x8f430350, 0x2402ffbf, 0x282a024,
-0x24630001, 0xaf430350, 0x100001d3, 0x8f420350,
-0x156a001d, 0x0, 0x8f430074, 0x8f420070,
-0x1062000a, 0x274b0074, 0x8f5e0074, 0xafab004c,
-0x27c20001, 0x304203ff, 0xafa20054, 0x1e1140,
-0x24426cc0, 0x1000004a, 0x2e2a821, 0x8f420044,
-0x8faa006c, 0x3c040001, 0x248468b8, 0x3c050007,
-0xafaa0014, 0xafa20010, 0x8f460074, 0x8f470070,
-0x34a51500, 0x240b0001, 0xc002b3b, 0xafab005c,
-0x1000ffc3, 0x0, 0x8f430064, 0x8f420060,
-0x1062001a, 0x274a0064, 0x8f5e0064, 0x8fab005c,
-0xafaa004c, 0x27c20001, 0x304200ff, 0xafa20054,
-0x24020004, 0x1562000e, 0x1e1140, 0x1e1180,
-0x24420cc0, 0x2e21021, 0xafa20044, 0x9442002a,
-0x8faa0044, 0x8fab006c, 0x4b102b, 0x10400024,
-0x25550020, 0x240a0001, 0x10000021, 0xa3aa0097,
-0x24424cc0, 0x1000001e, 0x2e2a821, 0x8f420044,
-0x8fab006c, 0x3c040001, 0x248468c4, 0xafab0014,
-0xafa20010, 0x8f460064, 0x8f470060, 0x3c050007,
-0xc002b3b, 0x34a51800, 0x3c020008, 0x2c21024,
-0x1440ff34, 0x0, 0x8f420370, 0x240a0001,
-0xafaa005c, 0x24420001, 0xaf420370, 0x1000ff90,
-0x8f420370, 0x27a30036, 0x131040, 0x621821,
-0x94620000, 0x441021, 0x10000020, 0xa4620000,
-0x8fab0064, 0xaeab0018, 0x93a20097, 0x10400072,
-0x9821, 0x8faa0044, 0x8fa4006c, 0x8fa300a4,
-0x25420020, 0xafa20028, 0x25420008, 0xafa20030,
-0x25420010, 0xafaa002c, 0xafa20034, 0x9542002a,
-0xa7a20038, 0x95420018, 0xa7a2003a, 0x9542001a,
-0xa7a2003c, 0x9542001c, 0xa7a2003e, 0x94620018,
-0x24630002, 0x822023, 0x1880ffde, 0x26730001,
-0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc,
-0x26650001, 0xa2102a, 0x1440002b, 0x24030001,
-0x8f83012c, 0x10600023, 0x0, 0x8f820124,
-0x431023, 0x22143, 0x58800001, 0x24840040,
-0x8f820128, 0x431023, 0x21943, 0x58600001,
-0x24630040, 0x64102a, 0x54400001, 0x602021,
-0xaf4400fc, 0x8f4200fc, 0xa2102a, 0x10400011,
-0x24030001, 0x10000015, 0x306200ff, 0x8fab0064,
-0x96070018, 0xafab0010, 0x8e220008, 0x3c040001,
-0x248468dc, 0x8c430004, 0x8c420000, 0x34a52400,
-0x2403021, 0xc002b3b, 0xafa30014, 0x1000002b,
-0x0, 0x8f420334, 0x1821, 0x24420001,
-0xaf420334, 0x8f420334, 0x306200ff, 0x5040fedc,
-0x3c020800, 0x12600021, 0x9021, 0x8fb100a4,
-0x2208021, 0x8e220008, 0x96070018, 0x8fa60064,
-0x8c440000, 0x8c450004, 0x240a0001, 0xafaa0010,
-0xafbe0014, 0x8f420008, 0xafa20018, 0x8f42010c,
-0x40f809, 0x0, 0x1040ffd8, 0x3c050007,
-0x96020018, 0x8fab0064, 0x8faa009c, 0x1625821,
-0x14b102b, 0x10400004, 0xafab0064, 0x8f420148,
-0x1625823, 0xafab0064, 0x26100002, 0x26520001,
-0x253102b, 0x1440ffe3, 0x26310004, 0x8fb0006c,
-0x10000036, 0x97b10038, 0x8f4200fc, 0x24050002,
-0xa2102a, 0x1440001b, 0x24030001, 0x8f83012c,
-0x10600013, 0x0, 0x8f820124, 0x431023,
-0x22143, 0x58800001, 0x24840040, 0x8f820128,
-0x431023, 0x21943, 0x58600001, 0x24630040,
-0x64102a, 0x54400001, 0x602021, 0xaf4400fc,
-0x8f4200fc, 0xa2102a, 0x14400006, 0x24030001,
-0x8f420334, 0x1821, 0x24420001, 0xaf420334,
-0x8f420334, 0x306200ff, 0x1040fea5, 0x3c020800,
-0x96b1000a, 0x8fb0006c, 0x3223ffff, 0x70102b,
-0x54400001, 0x608021, 0x8ea40000, 0x8ea50004,
-0x240b0001, 0xafab0010, 0xafbe0014, 0x8f420008,
-0x8fa60064, 0xafa20018, 0x8f42010c, 0x40f809,
-0x2003821, 0x1040fea2, 0x3c050007, 0x96a3000e,
-0x97aa008e, 0x11400007, 0x609021, 0x934205c4,
-0x14400004, 0x0, 0x97ab0086, 0x6a1825,
-0xa6ab0016, 0x8faa007c, 0x3c02ffff, 0x1421024,
-0x10400003, 0xa1402, 0x34630400, 0xa6a20014,
-0x8fab006c, 0x560b0072, 0xa6a3000e, 0x34620004,
-0xa6a2000e, 0x8faa0074, 0x16a1021, 0xa6a2000a,
-0x8f430044, 0x8f4401a0, 0x8f4501a4, 0x34028000,
-0xafa20010, 0x8f420044, 0x2a03021, 0x24070020,
-0xafa20014, 0x8f42000c, 0x31940, 0x604821,
-0xafa20018, 0x8f42010c, 0x4021, 0xa92821,
-0xa9182b, 0x882021, 0x40f809, 0x832021,
-0x5040fe7f, 0xa6b2000e, 0x8f420368, 0xafa0006c,
-0xa34005c4, 0x2442ffff, 0xaf420368, 0x8fab005c,
-0x240a0001, 0x8f420368, 0x156a0006, 0x240a0002,
-0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c,
-0x8f42035c, 0x156a0006, 0x0, 0x8f420364,
-0x2442ffff, 0xaf420364, 0x10000005, 0x8f420364,
-0x8f420360, 0x2442ffff, 0xaf420360, 0x8f420360,
-0x8faa0054, 0x8fab004c, 0xad6a0000, 0x8f420044,
-0x8f440088, 0x8f430078, 0x24420001, 0x441024,
-0x24630001, 0xaf420044, 0xaf430078, 0x8c020240,
-0x62182b, 0x14600075, 0x24070008, 0x8f440168,
-0x8f45016c, 0x8f430044, 0x8f48000c, 0x8f860120,
-0x24020040, 0xafa20010, 0xafa30014, 0xafa80018,
-0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
-0x240b0001, 0x3c010001, 0x370821, 0xa02b40f2,
-0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
-0x2484688c, 0xafa20014, 0x8f460044, 0x8f870120,
-0x3c050009, 0xc002b3b, 0x34a51300, 0x1000000b,
-0x0, 0x8f420304, 0x24420001, 0xaf420304,
-0x8f420304, 0x8f420044, 0xaf42007c, 0x3c010001,
-0x370821, 0xa02040f2, 0xaf400078, 0x8f420318,
-0x24420001, 0xaf420318, 0x10000048, 0x8f420318,
-0xa6b0000a, 0x8f430044, 0x8f4401a0, 0x8f4501a4,
-0x34028000, 0xafa20010, 0x8f420044, 0x2a03021,
-0x24070020, 0xafa20014, 0x8f42000c, 0x31940,
-0x604821, 0xafa20018, 0x8f42010c, 0x4021,
-0xa92821, 0xa9182b, 0x882021, 0x40f809,
-0x832021, 0x1040fe1f, 0x240a0001, 0xa34a05c4,
-0x8fab006c, 0x8faa0064, 0x1705823, 0xafab006c,
-0x8fab009c, 0x1505021, 0x16a102b, 0x10400004,
-0xafaa0064, 0x8f420148, 0x1425023, 0xafaa0064,
-0x8f420368, 0x2442ffff, 0xaf420368, 0x8faa005c,
-0x240b0001, 0x8f420368, 0x154b0006, 0x240b0002,
-0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c,
-0x8f42035c, 0x114b0006, 0x0, 0x8f420360,
-0x2442ffff, 0xaf420360, 0x10000005, 0x8f420360,
-0x8f420364, 0x2442ffff, 0xaf420364, 0x8f420364,
-0x8fab0054, 0x8faa004c, 0xad4b0000, 0x8f420044,
-0x8f440088, 0x8f430078, 0x24420001, 0x441024,
-0x24630001, 0xaf420044, 0xaf430078, 0x8faa006c,
-0x1540fe0b, 0x0, 0x8fab006c, 0x1160001e,
-0x0, 0x934205c4, 0x10400009, 0x0,
-0x8faa0064, 0xaf4a00c4, 0xaf4b00c0, 0x8fab007c,
-0xaf4b00c8, 0x8faa0074, 0x1000000e, 0xaf4a00cc,
-0x97ab008e, 0x1160000b, 0x34038100, 0x8fa20020,
-0x8c46000c, 0xa443000c, 0x97aa0086, 0x8c440004,
-0x8c450008, 0xa44a000e, 0xac440000, 0xac450004,
-0xac460008, 0x8f42034c, 0x24420001, 0xaf42034c,
-0x10000010, 0x8f42034c, 0x8fab007c, 0x3164ffff,
-0x2484fffc, 0x801821, 0x8f440250, 0x8f450254,
-0x8f460118, 0x1021, 0xa32821, 0xa3382b,
-0x822021, 0x872021, 0xaf440250, 0xc0f809,
-0xaf450254, 0x8fbf00c8, 0x8fbe00c4, 0x8fb500c0,
-0x8fb300bc, 0x8fb200b8, 0x8fb100b4, 0x8fb000b0,
-0x3e00008, 0x27bd00d0, 0x3e00008, 0x0,
-0x27bdff38, 0x240b0001, 0xafbf00c0, 0xafbe00bc,
-0xafb500b8, 0xafb300b4, 0xafb200b0, 0xafb100ac,
-0xafb000a8, 0xa3a00087, 0xafa00044, 0xafab005c,
-0x934205c4, 0xa7a00076, 0x10400007, 0xa7a0007e,
-0x8f4c00c0, 0xafac0064, 0x8f4b00c8, 0x8f5e00c4,
-0x10000130, 0xafab006c, 0x8f420114, 0x40f809,
-0x0, 0x403021, 0x10c002a1, 0x0,
-0x8cc20000, 0x8cc30004, 0xafa20020, 0xafa30024,
-0x8fac0024, 0x8fbe0020, 0x3182ffff, 0x2442fffc,
-0xafa20064, 0x3c020006, 0x2c21024, 0x14400015,
-0xafac006c, 0x93c20000, 0x30420001, 0x10400011,
-0x2402ffff, 0x8fc30000, 0x14620004, 0x3402ffff,
-0x97c30004, 0x1062000b, 0x0, 0xc0024bb,
-0x3c02021, 0x304200ff, 0x14400006, 0x0,
-0x8f420118, 0x40f809, 0x0, 0x10000280,
-0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff,
-0x431024, 0x3c03ffff, 0x431824, 0x14600003,
-0xafa20024, 0x10000040, 0x8021, 0x3c020080,
-0x621024, 0x10400007, 0x0, 0x8f42038c,
-0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036,
-0x24100001, 0x8f420210, 0x24420001, 0xaf420210,
-0x8f420210, 0x3c020001, 0x621024, 0x10400006,
-0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4,
-0x8f4201c4, 0x3c020002, 0x621024, 0x10400006,
-0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c,
-0x8f42037c, 0x3c020004, 0x621024, 0x10400006,
-0x3c020008, 0x8f420380, 0x24420001, 0xaf420380,
-0x8f420380, 0x3c020008, 0x621024, 0x10400006,
-0x3c020010, 0x8f420384, 0x24420001, 0xaf420384,
-0x8f420384, 0x3c020010, 0x621024, 0x10400006,
-0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0,
-0x8f4201c0, 0x3c020020, 0x621024, 0x10400006,
-0x24100001, 0x8f420388, 0x24420001, 0xaf420388,
-0x8f420388, 0x24100001, 0x8c020260, 0x8fab0064,
-0x4b102b, 0x10400015, 0x320200ff, 0x8f4201e8,
-0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8fac006c,
-0x8f8200e0, 0x358c0100, 0xafac006c, 0xafa20010,
-0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0,
-0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007,
-0xc002b3b, 0x34a53600, 0x320200ff, 0x10400010,
-0x3c020080, 0x2c21024, 0x1440000e, 0x32c20400,
-0x8fab006c, 0x3c020080, 0x34420100, 0x1621024,
-0x10400005, 0x0, 0x8f42020c, 0x24420001,
-0xaf42020c, 0x8f42020c, 0x10000202, 0x8fa30064,
-0x32c20400, 0x10400012, 0x34028100, 0x97c3000c,
-0x1462000f, 0x0, 0x240c0200, 0xa7ac0076,
-0x97c2000e, 0x8fc30008, 0x8fc40004, 0x8fab0064,
-0x8fc50000, 0x256bfffc, 0xafab0064, 0xa7a2007e,
-0xafc3000c, 0xafc40008, 0xafc50004, 0x27de0004,
-0x8fa70064, 0x320200ff, 0x14400034, 0x3c020100,
-0x97c4000c, 0x2c8305dd, 0x38828870, 0x2c420001,
-0x621825, 0x10600015, 0x2821, 0x32c20800,
-0x10400015, 0x24020800, 0x97c30014, 0x14620012,
-0x3402aaaa, 0x97c3000e, 0x14620007, 0x2021,
-0x97c30010, 0x24020300, 0x14620004, 0x801021,
-0x97c20012, 0x2c440001, 0x801021, 0x54400006,
-0x24050016, 0x10000004, 0x0, 0x24020800,
-0x50820001, 0x2405000e, 0x10a00013, 0x3c52021,
-0x24830009, 0x3c02001f, 0x3442ffff, 0x43102b,
-0x10400003, 0x0, 0x8f420148, 0x621823,
-0x90620000, 0x38430006, 0x2c630001, 0x38420011,
-0x2c420001, 0x621825, 0x10600004, 0x3c020100,
-0x94820002, 0x453821, 0x3c020100, 0x2c21024,
-0x5040000e, 0xafa70064, 0x8fac0064, 0x10ec0008,
-0x3c050007, 0x3c040001, 0x24846908, 0x8fa60064,
-0x34a54000, 0xafa00010, 0xc002b3b, 0xafa00014,
-0x8fab0064, 0x256b0004, 0xafab0064, 0x8f420080,
-0x8fac0064, 0x4c102b, 0x1040002c, 0x32c28000,
-0x10400034, 0x240b0003, 0x32c21000, 0x10400031,
-0xafab005c, 0x1000002e, 0x240c0004, 0x8f420350,
-0x2403ffbf, 0x283a024, 0x24420001, 0xaf420350,
-0x10000173, 0x8f420350, 0x3c020800, 0x2c2b025,
-0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001,
-0x248468d0, 0x26620001, 0xafa20014, 0xafa30010,
-0x8f860120, 0x8f870124, 0x3c050007, 0xc002b3b,
-0x34a55300, 0x10000162, 0x0, 0x8ea20000,
-0x8ea30004, 0x3c040001, 0x248468e8, 0xafb00010,
-0xafb10014, 0x8ea70018, 0x34a55900, 0xc002b3b,
-0x603021, 0x10000156, 0x0, 0x8f420084,
-0x8fab0064, 0x4b102b, 0x14400007, 0x3c020001,
-0x2c21024, 0x10400004, 0x0, 0x240c0002,
-0xafac005c, 0x8fab0064, 0x11600166, 0x27ac0020,
-0xafac008c, 0x8fab005c, 0x240c0001, 0x556c0021,
-0x240c0002, 0x8f430054, 0x8f420050, 0x1062000b,
-0x274b0054, 0x8f510054, 0x3403ecc0, 0xafab004c,
-0x26220001, 0x304201ff, 0xafa20054, 0x111140,
-0x431021, 0x1000006b, 0x2e2a821, 0x8f420044,
-0x8fac0064, 0x3c040001, 0x248468ac, 0xafac0014,
-0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007,
-0xc002b3b, 0x34a54300, 0x8f430350, 0x2402ffbf,
-0x282a024, 0x24630001, 0xaf430350, 0x10000124,
-0x8f420350, 0x156c001d, 0x0, 0x8f430074,
-0x8f420070, 0x1062000a, 0x274b0074, 0x8f510074,
-0xafab004c, 0x26220001, 0x304203ff, 0xafa20054,
-0x111140, 0x24426cc0, 0x1000004a, 0x2e2a821,
-0x8f420044, 0x8fac0064, 0x3c040001, 0x248468b8,
-0x3c050007, 0xafac0014, 0xafa20010, 0x8f460074,
-0x8f470070, 0x34a54500, 0x240b0001, 0xc002b3b,
-0xafab005c, 0x1000ffc3, 0x0, 0x8f430064,
-0x8f420060, 0x1062001a, 0x274c0064, 0x8f510064,
-0x8fab005c, 0xafac004c, 0x26220001, 0x304200ff,
-0xafa20054, 0x24020004, 0x1562000e, 0x111140,
-0x111180, 0x24420cc0, 0x2e21021, 0xafa20044,
-0x9442002a, 0x8fac0044, 0x8fab0064, 0x4b102b,
-0x10400024, 0x25950020, 0x240c0001, 0x10000021,
-0xa3ac0087, 0x24424cc0, 0x1000001e, 0x2e2a821,
-0x8f420044, 0x8fab0064, 0x3c040001, 0x248468c4,
-0xafab0014, 0xafa20010, 0x8f460064, 0x8f470060,
-0x3c050007, 0xc002b3b, 0x34a54800, 0x3c020008,
-0x2c21024, 0x1440ff61, 0x0, 0x8f420370,
-0x240c0001, 0xafac005c, 0x24420001, 0xaf420370,
-0x1000ff90, 0x8f420370, 0x27a30036, 0x131040,
-0x621821, 0x94620000, 0x441021, 0x1000001f,
-0xa4620000, 0xaebe0018, 0x93a20087, 0x10400084,
-0x9821, 0x8fab0044, 0x8fa40064, 0x8fa3008c,
-0x25620020, 0xafa20028, 0x25620008, 0xafa20030,
-0x25620010, 0xafab002c, 0xafa20034, 0x9562002a,
-0xa7a20038, 0x95620018, 0xa7a2003a, 0x9562001a,
-0xa7a2003c, 0x9562001c, 0xa7a2003e, 0x94620018,
-0x24630002, 0x822023, 0x1880ffdf, 0x26730001,
-0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc,
-0x262102a, 0x14400030, 0x24030001, 0x8f83012c,
-0x10600028, 0x0, 0x8f820124, 0x431023,
-0x22143, 0x58800001, 0x24840040, 0x8f820128,
-0x431023, 0x21943, 0x58600001, 0x24630040,
-0x64102a, 0x54400001, 0x602021, 0xaf4400fc,
-0x8f4200fc, 0x262102a, 0x10400016, 0x24030001,
-0x1000001a, 0x306200ff, 0x8fac008c, 0x101040,
-0x4c1021, 0x94470018, 0x101080, 0x4c1021,
-0xafbe0010, 0x8c420008, 0x3c040001, 0x248468dc,
-0x3c050007, 0x8c430004, 0x8c420000, 0x34a55500,
-0x2003021, 0xc002b3b, 0xafa30014, 0x10000039,
-0x0, 0x8f420334, 0x1821, 0x24420001,
-0xaf420334, 0x8f420334, 0x306200ff, 0x1040ff06,
-0x8021, 0x8f430008, 0x2402fbff, 0x1260002d,
-0x625024, 0x3c0b4000, 0x22b4025, 0x8fb1008c,
-0x2669ffff, 0x2209021, 0x8e420008, 0x96270018,
-0x8c440000, 0x8c450004, 0x56090004, 0x240b0001,
-0x240c0002, 0x10000002, 0xafac0010, 0xafab0010,
-0x16000004, 0xafa80014, 0x8f420008, 0x10000002,
-0xafa20018, 0xafaa0018, 0x8f42010c, 0x3c03021,
-0xafa80098, 0xafa9009c, 0x40f809, 0xafaa00a0,
-0x8fa80098, 0x8fa9009c, 0x8faa00a0, 0x1040ffc2,
-0x3c02001f, 0x96230018, 0x3442ffff, 0x3c3f021,
-0x5e102b, 0x10400003, 0x26310002, 0x8f420148,
-0x3c2f023, 0x26100001, 0x213102b, 0x1440ffda,
-0x26520004, 0x8fb00064, 0x1000001a, 0x0,
-0x96a3000a, 0x8fb00064, 0x70102b, 0x54400001,
-0x608021, 0x8ea40000, 0x8ea50004, 0x8fab005c,
-0x240c0002, 0xafac0010, 0x934305c4, 0xb1700,
-0x10600003, 0x2223025, 0x3c020800, 0xc23025,
-0xafa60014, 0x8f420008, 0xafa20018, 0x8f42010c,
-0x3c03021, 0x40f809, 0x2003821, 0x1040fecb,
-0x3c050007, 0x97ac0076, 0x11800007, 0x96a3000e,
-0x934205c4, 0x14400004, 0x0, 0x97ab007e,
-0x6c1825, 0xa6ab0016, 0x8fac006c, 0x3c02ffff,
-0x1821024, 0x10400003, 0xc1402, 0x34630400,
-0xa6a20014, 0xa6b0000a, 0x8fab0064, 0x560b0006,
-0x3d0f021, 0x34620004, 0xafa00064, 0xa6a2000e,
-0x1000000d, 0xa34005c4, 0x8fac0064, 0x3c02001f,
-0x3442ffff, 0x5e102b, 0x1906023, 0xafac0064,
-0xa6a3000e, 0x240b0001, 0x10400003, 0xa34b05c4,
-0x8f420148, 0x3c2f023, 0x8fab0054, 0x8fac004c,
-0xad8b0000, 0x8fac0064, 0x1580feba, 0x0,
-0x8fab0064, 0x1160001b, 0x0, 0x934205c4,
-0x10400006, 0x0, 0xaf5e00c4, 0xaf4b00c0,
-0x8fac006c, 0x1000000e, 0xaf4c00c8, 0x97ab0076,
-0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c,
-0xa443000c, 0x97ac007e, 0x8c440004, 0x8c450008,
-0xa44c000e, 0xac440000, 0xac450004, 0xac460008,
-0x8f42034c, 0x24420001, 0xaf42034c, 0x10000010,
-0x8f42034c, 0x8fab006c, 0x3164ffff, 0x2484fffc,
-0x801821, 0x8f440250, 0x8f450254, 0x8f460118,
-0x1021, 0xa32821, 0xa3382b, 0x822021,
-0x872021, 0xaf440250, 0xc0f809, 0xaf450254,
-0x8fbf00c0, 0x8fbe00bc, 0x8fb500b8, 0x8fb300b4,
-0x8fb200b0, 0x8fb100ac, 0x8fb000a8, 0x3e00008,
-0x27bd00c8, 0x3e00008, 0x0, 0x27bdffd8,
-0xafbf0024, 0xafb00020, 0x8f43004c, 0x8f420048,
-0x10620034, 0x0, 0x8f430048, 0x8f42004c,
-0x622023, 0x4820001, 0x24840200, 0x8f430054,
-0x8f42004c, 0x43102b, 0x14400004, 0x24020200,
-0x8f43004c, 0x10000005, 0x431023, 0x8f420054,
-0x8f43004c, 0x431023, 0x2442ffff, 0x405021,
-0x8a102a, 0x54400001, 0x805021, 0x8f49004c,
-0x8f48004c, 0x8f440188, 0x8f45018c, 0x8f46004c,
-0x24071000, 0xafa70010, 0x84140, 0x1001821,
-0x12a4821, 0x313001ff, 0xafb00014, 0x8f470014,
-0x1021, 0x63140, 0xafa70018, 0xa32821,
-0xa3382b, 0x822021, 0x872021, 0x3402ecc0,
-0xc23021, 0x8f420108, 0x2e63021, 0x40f809,
-0xa3940, 0x54400001, 0xaf50004c, 0x8f43004c,
-0x8f420048, 0x14620018, 0x0, 0x8f420000,
-0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x10000002,
-0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020,
-0x3e00008, 0x27bd0028, 0x3e00008, 0x0,
-0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43005c,
-0x8f420058, 0x10620049, 0x0, 0x8f430058,
-0x8f42005c, 0x622023, 0x4820001, 0x24840100,
-0x8f430064, 0x8f42005c, 0x43102b, 0x14400004,
-0x24020100, 0x8f43005c, 0x10000005, 0x431023,
-0x8f420064, 0x8f43005c, 0x431023, 0x2442ffff,
-0x403821, 0x87102a, 0x54400001, 0x803821,
-0x8f42005c, 0x471021, 0x305000ff, 0x32c21000,
-0x10400015, 0x24082000, 0x8f49005c, 0x8f440190,
-0x8f450194, 0x8f46005c, 0x73980, 0xafa80010,
-0xafb00014, 0x8f480014, 0x94980, 0x1201821,
-0x1021, 0xa32821, 0xa3482b, 0x822021,
-0x892021, 0x63180, 0xafa80018, 0x8f420108,
-0x10000014, 0x24c60cc0, 0x8f49005c, 0x8f440190,
-0x8f450194, 0x8f46005c, 0x73940, 0xafa80010,
-0xafb00014, 0x8f480014, 0x94940, 0x1201821,
-0x1021, 0xa32821, 0xa3482b, 0x822021,
-0x892021, 0x63140, 0xafa80018, 0x8f420108,
-0x24c64cc0, 0x40f809, 0x2e63021, 0x54400001,
-0xaf50005c, 0x8f43005c, 0x8f420058, 0x14620018,
-0x0, 0x8f420000, 0x10400007, 0x0,
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
-0x10000005, 0x0, 0xaf800048, 0x8f820048,
-0x1040fffd, 0x0, 0x8f820060, 0x2403feff,
-0x431024, 0xaf820060, 0x8f420000, 0x10400003,
-0x0, 0x10000002, 0xaf80004c, 0xaf800048,
-0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028,
-0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
-0xafb00020, 0x8f43006c, 0x8f420068, 0x10620033,
-0x0, 0x8f430068, 0x8f42006c, 0x622023,
-0x4820001, 0x24840400, 0x8f430074, 0x8f42006c,
-0x43102b, 0x14400004, 0x24020400, 0x8f43006c,
-0x10000005, 0x431023, 0x8f420074, 0x8f43006c,
-0x431023, 0x2442ffff, 0x405021, 0x8a102a,
-0x54400001, 0x805021, 0x8f49006c, 0x8f48006c,
-0x8f440198, 0x8f45019c, 0x8f46006c, 0x24074000,
-0xafa70010, 0x84140, 0x1001821, 0x12a4821,
-0x313003ff, 0xafb00014, 0x8f470014, 0x1021,
-0x63140, 0x24c66cc0, 0xafa70018, 0xa32821,
-0xa3382b, 0x822021, 0x872021, 0x8f420108,
-0x2e63021, 0x40f809, 0xa3940, 0x54400001,
-0xaf50006c, 0x8f43006c, 0x8f420068, 0x14620018,
-0x0, 0x8f420000, 0x10400007, 0x0,
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
-0x10000005, 0x0, 0xaf800048, 0x8f820048,
-0x1040fffd, 0x0, 0x8f820060, 0x2403f7ff,
-0x431024, 0xaf820060, 0x8f420000, 0x10400003,
-0x0, 0x10000002, 0xaf80004c, 0xaf800048,
-0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028,
-0x3e00008, 0x0, 0x8f4200fc, 0x3c030001,
-0x8f4400f8, 0x346330c8, 0x24420001, 0xaf4200fc,
-0x8f850128, 0x2e31021, 0x54820004, 0x24820008,
-0x3c020001, 0x34422ec8, 0x2e21021, 0x401821,
-0xaf4300f8, 0xac600000, 0x8f4200f4, 0x14620004,
-0x3c020001, 0x24a20020, 0x1000000f, 0xaf820128,
-0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004,
-0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021,
-0x401821, 0x8c620004, 0x21140, 0xa21021,
-0xaf820128, 0xac600000, 0x8ca30018, 0x30620070,
-0x1040002d, 0x30620020, 0x10400004, 0x3c020010,
-0x2c21024, 0x1040000d, 0x0, 0x30620040,
-0x10400004, 0x3c020020, 0x2c21024, 0x10400007,
-0x0, 0x30620010, 0x1040001f, 0x3c020040,
-0x2c21024, 0x1440001c, 0x0, 0x8f820040,
-0x30420001, 0x14400008, 0x2021, 0x8c030104,
-0x24020001, 0x50620005, 0x24040001, 0x8c020264,
-0x10400003, 0x801021, 0x24040001, 0x801021,
-0x10400006, 0x0, 0x8f42030c, 0x24420001,
-0xaf42030c, 0x10000008, 0x8f42030c, 0x8f820044,
-0x34420004, 0xaf820044, 0x8f420308, 0x24420001,
-0xaf420308, 0x8f420308, 0x3e00008, 0x0,
-0x3e00008, 0x0, 0x27bdff98, 0xafbf0060,
-0xafbe005c, 0xafb50058, 0xafb30054, 0xafb20050,
-0xafb1004c, 0xafb00048, 0x8f4200fc, 0x24420001,
-0xaf4200fc, 0x8f880128, 0x25020020, 0xaf820128,
-0x8d030018, 0x30620070, 0x1040002e, 0x30620020,
-0x10400004, 0x3c020010, 0x2c21024, 0x1040000d,
-0x0, 0x30620040, 0x10400004, 0x3c020020,
-0x2c21024, 0x10400007, 0x0, 0x30620010,
-0x104001a9, 0x3c020040, 0x2c21024, 0x144001a6,
-0x0, 0x8f820040, 0x30420001, 0x14400008,
-0x2021, 0x8c030104, 0x24020001, 0x50620005,
-0x24040001, 0x8c020264, 0x10400003, 0x801021,
-0x24040001, 0x801021, 0x10400006, 0x0,
-0x8f42030c, 0x24420001, 0xaf42030c, 0x10000192,
-0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044,
-0x8f420308, 0x24420001, 0xaf420308, 0x1000018a,
-0x8f420308, 0x30620002, 0x1040014b, 0x3c020800,
-0x8d1e001c, 0x1e5702, 0xafaa0034, 0x950a0016,
-0x3c22024, 0xafaa0024, 0x8faa0034, 0x24020001,
-0x15420006, 0x33deffff, 0x1e1140, 0x3403ecc0,
-0x431021, 0x10000010, 0x2e2a821, 0x24020002,
-0x15420005, 0x24020003, 0x1e1140, 0x24426cc0,
-0x10000009, 0x2e2a821, 0x15420005, 0x1e1180,
-0x1e1140, 0x24424cc0, 0x10000003, 0x2e2a821,
-0x571021, 0x24550ce0, 0x96a2000e, 0x304afffc,
-0x30420400, 0x10400003, 0xafaa002c, 0x100000e1,
-0x8821, 0x10800004, 0x8821, 0x97b10026,
-0x100000dd, 0xa6b10012, 0x8eb30018, 0x966a000c,
-0xa7aa003e, 0x97a5003e, 0x2ca305dd, 0x38a28870,
-0x2c420001, 0x621825, 0x10600015, 0x2021,
-0x32c20800, 0x10400015, 0x24020800, 0x96630014,
-0x14620012, 0x3402aaaa, 0x9663000e, 0x14620007,
-0x2821, 0x96630010, 0x24020300, 0x14620004,
-0xa01021, 0x96620012, 0x2c450001, 0xa01021,
-0x54400006, 0x24040016, 0x10000004, 0x0,
-0x24020800, 0x50a20001, 0x2404000e, 0x108000b9,
-0x2649021, 0x92420000, 0x3042000f, 0x28080,
-0x32c20100, 0x10400020, 0x2501821, 0x3c020020,
-0x43102b, 0x1440000e, 0x2402021, 0x2821,
-0x94820000, 0x24840002, 0xa22821, 0x83102b,
-0x1440fffb, 0x30a2ffff, 0x51c02, 0x622821,
-0x51c02, 0x30a2ffff, 0x10000009, 0x622821,
-0x8f470148, 0x8f420110, 0x102842, 0x3c060020,
-0x40f809, 0xafa80040, 0x3045ffff, 0x8fa80040,
-0x50a00001, 0x3405ffff, 0x8faa002c, 0x354a0002,
-0x10000002, 0xafaa002c, 0x2821, 0x32c20080,
-0x10400090, 0xa6a50010, 0x26430009, 0x3c02001f,
-0x3442ffff, 0x43102b, 0x10400003, 0x0,
-0x8f420148, 0x621823, 0x90660000, 0x30c200ff,
-0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
-0x621825, 0x1060007f, 0x24020800, 0x8821,
-0x97a3003e, 0x1462000f, 0x2602021, 0x96710000,
-0x96620002, 0x96630004, 0x96640006, 0x2228821,
-0x2238821, 0x2248821, 0x96620008, 0x9663000a,
-0x9664000c, 0x2228821, 0x2238821, 0x10000007,
-0x2248821, 0x94820000, 0x24840002, 0x2228821,
-0x92102b, 0x1440fffb, 0x0, 0x111c02,
-0x3222ffff, 0x628821, 0x111c02, 0x3222ffff,
-0x628821, 0x32c20200, 0x10400003, 0x26440006,
-0x1000003e, 0x8021, 0x3c05001f, 0x34a5ffff,
-0xa4102b, 0x10400003, 0x0, 0x8f420148,
-0x822023, 0x94820000, 0x30421fff, 0x10400004,
-0x2644000c, 0x96420002, 0x10000030, 0x508023,
-0x96420002, 0x26430014, 0x508023, 0x3c020020,
-0x43102b, 0x1440000a, 0xd08021, 0x9642000c,
-0x2028021, 0x9642000e, 0x96430010, 0x96440012,
-0x2028021, 0x2038021, 0x10000020, 0x2048021,
-0xa4102b, 0x10400003, 0x0, 0x8f420148,
-0x822023, 0x94820000, 0x24840002, 0x2028021,
-0xa4102b, 0x10400003, 0x0, 0x8f420148,
-0x822023, 0x94820000, 0x24840002, 0x2028021,
-0xa4102b, 0x10400003, 0x0, 0x8f420148,
-0x822023, 0x94820000, 0x24840002, 0x2028021,
-0xa4102b, 0x10400003, 0x0, 0x8f420148,
-0x822023, 0x94820000, 0x2028021, 0x3c020100,
-0x2c21024, 0x1040000e, 0x0, 0x8faa002c,
-0x31420004, 0x1040000a, 0x0, 0x9504000e,
-0x2642021, 0xc003eec, 0x2484fffc, 0x3042ffff,
-0x2228821, 0x111c02, 0x3222ffff, 0x628821,
-0x8faa0024, 0x1518823, 0x111402, 0x2228821,
-0x2308821, 0x111402, 0x2228821, 0x3231ffff,
-0x52200001, 0x3411ffff, 0x8faa002c, 0x354a0001,
-0xafaa002c, 0xa6b10012, 0x97aa002e, 0xa6aa000e,
-0x8faa002c, 0x31420004, 0x10400002, 0x24091000,
-0x34098000, 0x8f480044, 0x8f4401a0, 0x8f4501a4,
-0xafa90010, 0x8f490044, 0x84140, 0x1001821,
-0xafa90014, 0x8f48000c, 0x2a03021, 0x24070020,
-0xafa80018, 0x8f48010c, 0x1021, 0xa32821,
-0xa3482b, 0x822021, 0x100f809, 0x892021,
-0x1440000b, 0x0, 0x8f820128, 0x3c040001,
-0x24846914, 0xafbe0014, 0xafa20010, 0x8f860124,
-0x8f870120, 0x3c050007, 0xc002b3b, 0x34a59920,
-0x8f420368, 0x2442ffff, 0xaf420368, 0x8f420044,
-0x8f430088, 0x24420001, 0x431024, 0xaf420044,
-0x8faa0034, 0x8f440368, 0x24020001, 0x15420006,
-0x24020002, 0x8f42035c, 0x2442ffff, 0xaf42035c,
-0x10000049, 0x8f42035c, 0x15420006, 0x0,
-0x8f420364, 0x2442ffff, 0xaf420364, 0x10000042,
-0x8f420364, 0x8f420360, 0x2442ffff, 0xaf420360,
-0x1000003d, 0x8f420360, 0x30621000, 0x10400005,
-0x30628000, 0x8f420078, 0x24420001, 0x10000036,
-0xaf420078, 0x10400034, 0x0, 0x8f420078,
-0x24420001, 0xaf420078, 0x8c030240, 0x43102b,
-0x1440002d, 0x24070008, 0x8f440168, 0x8f45016c,
-0x8f430044, 0x8f48000c, 0x8f860120, 0x24020040,
-0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
-0x40f809, 0x24c6001c, 0x14400011, 0x24020001,
-0x3c010001, 0x370821, 0xa02240f2, 0x8f820124,
-0xafa20010, 0x8f820128, 0x3c040001, 0x2484688c,
-0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009,
-0xc002b3b, 0x34a51300, 0x1000000b, 0x0,
-0x8f420304, 0x24420001, 0xaf420304, 0x8f420304,
-0x8f420044, 0xaf42007c, 0x3c010001, 0x370821,
-0xa02040f2, 0xaf400078, 0x8f420318, 0x24420001,
-0xaf420318, 0x8f420318, 0x8fbf0060, 0x8fbe005c,
-0x8fb50058, 0x8fb30054, 0x8fb20050, 0x8fb1004c,
-0x8fb00048, 0x3e00008, 0x27bd0068, 0x3e00008,
-0x0, 0x0, 0x0, 0x8f42013c,
-0xaf8200c0, 0x8f42013c, 0xaf8200c4, 0x8f42013c,
-0xaf8200c8, 0x8f420138, 0xaf8200d0, 0x8f420138,
-0xaf8200d4, 0x8f420138, 0x3e00008, 0xaf8200d8,
-0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018,
-0xc002bbf, 0x24060008, 0x8c020204, 0xc004012,
-0xaf820210, 0x3c020001, 0x8c426d94, 0x30420002,
-0x1040000e, 0x2021, 0x8c060248, 0x24020002,
-0x3c010001, 0xac226d98, 0xc005104, 0x24050002,
-0x2021, 0x8c060248, 0x24020001, 0x3c010001,
-0xac226d98, 0x10000011, 0x24050001, 0x8c060248,
-0x24020004, 0x3c010001, 0xac226d98, 0xc005104,
-0x24050004, 0x3c020001, 0x8c426d94, 0x30420001,
-0x10400008, 0x24020001, 0x3c010001, 0xac226d98,
-0x2021, 0x24050001, 0x3c06601b, 0xc005104,
-0x0, 0x3c040001, 0x248469d0, 0x8f420150,
-0x8f430154, 0x3c050008, 0x8f460158, 0x21640,
-0x31940, 0x34630403, 0x431025, 0x633c0,
-0x461025, 0xaf82021c, 0xafa00010, 0xafa00014,
-0x8f86021c, 0x34a50200, 0xc002b3b, 0x3821,
-0x3c010001, 0xac206d90, 0x3c010001, 0xac206da8,
-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0,
-0x3c050008, 0x34a50300, 0xafbf0018, 0xafa00010,
-0xafa00014, 0x8f860200, 0x3c040001, 0x248469dc,
-0xc002b3b, 0x3821, 0x8f420410, 0x24420001,
-0xaf420410, 0x8f420410, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb1001c,
-0xafb00018, 0x8f4203a4, 0x24420001, 0xaf4203a4,
-0x8f4203a4, 0x8f900220, 0x8f8200e0, 0xafa20010,
-0x8f8200e4, 0xafa20014, 0x8f8600c4, 0x8f8700c8,
-0x3c040001, 0x248469e8, 0xc002b3b, 0x2002821,
-0x3c044000, 0x2041024, 0x504000b4, 0x3c040100,
-0x8f4203bc, 0x24420001, 0xaf4203bc, 0x8f4203bc,
-0x8f8700c4, 0x8f8300c8, 0x8f420148, 0x671823,
-0x43102b, 0x10400003, 0x0, 0x8f420148,
-0x621821, 0x10600005, 0x0, 0x8f42014c,
-0x43102b, 0x1040000b, 0x0, 0x8f8200e0,
-0x8f430124, 0xaf42011c, 0xaf430114, 0x8f820220,
-0x3c0308ff, 0x3463fffb, 0x431024, 0x100000ce,
-0x441025, 0x8f820220, 0x3c0308ff, 0x3463ffff,
-0x431024, 0x34420004, 0xaf820220, 0x8f8200e0,
-0x8f430124, 0xaf42011c, 0xaf430114, 0x8f8600c8,
-0x8f840120, 0x8f830124, 0x10000005, 0x2821,
-0x14620002, 0x24620020, 0x27624800, 0x401821,
-0x1064000c, 0x30a200ff, 0x8c620018, 0x30420003,
-0x1040fff7, 0x27624fe0, 0x8f4203d0, 0x24050001,
-0x24420001, 0xaf4203d0, 0x8f4203d0, 0x8c660008,
-0x30a200ff, 0x14400058, 0x0, 0x934205c4,
-0x14400055, 0x0, 0x8f8700c4, 0x8f8800e0,
-0x8f8400e4, 0x2402fff8, 0x1024024, 0x1041023,
-0x218c3, 0x4620001, 0x24630200, 0x10600005,
-0x24020001, 0x10620009, 0x0, 0x1000001f,
-0x0, 0x8f4203c0, 0xe03021, 0x24420001,
-0xaf4203c0, 0x10000040, 0x8f4203c0, 0x8f4203c4,
-0x24420001, 0xaf4203c4, 0x8c860000, 0x8f420148,
-0x8f4303c4, 0xe61823, 0x43102b, 0x10400004,
-0x2c62233f, 0x8f420148, 0x621821, 0x2c62233f,
-0x14400031, 0x0, 0x8f42020c, 0x24420001,
-0xaf42020c, 0x8f42020c, 0xe03021, 0x24820008,
-0xaf8200e4, 0x10000028, 0xaf8200e8, 0x8f4203c8,
-0x24420001, 0xaf4203c8, 0x8f4203c8, 0x8c850000,
-0x8f420148, 0xa71823, 0x43102b, 0x10400003,
-0x0, 0x8f420148, 0x621821, 0x8f42014c,
-0x43102b, 0x5440000a, 0xa03021, 0x8f42020c,
-0x24420001, 0xaf42020c, 0x8f42020c, 0x24820008,
-0xaf8200e4, 0x8f8400e4, 0x1488ffec, 0xaf8400e8,
-0x1488000d, 0x27623000, 0x14820002, 0x2482fff8,
-0x27623ff8, 0x94430006, 0x3c02001f, 0x3442ffff,
-0xc33021, 0x46102b, 0x10400003, 0x0,
-0x8f420148, 0xc23023, 0xaf8600c8, 0x8f8300c4,
-0x8f420148, 0xc31823, 0x43102b, 0x10400003,
-0x0, 0x8f420148, 0x621821, 0x10600005,
-0x0, 0x8f42014c, 0x43102b, 0x50400008,
-0x3c02fdff, 0x8f820220, 0x3c0308ff, 0x3463fffb,
-0x431024, 0x3c034000, 0x1000003f, 0x431025,
-0x8f4303cc, 0x3442ffff, 0x282a024, 0x24630001,
-0xaf4303cc, 0x10000039, 0x8f4203cc, 0x2041024,
-0x1040000e, 0x3c110200, 0x8f4203a8, 0x24420001,
-0xaf4203a8, 0x8f4203a8, 0x8f820220, 0x3c0308ff,
-0x3463ffff, 0x431024, 0x441025, 0xc003daf,
-0xaf820220, 0x10000029, 0x0, 0x2111024,
-0x50400008, 0x3c110400, 0x8f4203ac, 0x24420001,
-0xaf4203ac, 0xc003daf, 0x8f4203ac, 0x10000019,
-0x0, 0x2111024, 0x1040001c, 0x0,
-0x8f830224, 0x24021402, 0x14620009, 0x3c050008,
-0x3c040001, 0x248469f4, 0xafa00010, 0xafa00014,
-0x8f860224, 0x34a50500, 0xc002b3b, 0x3821,
-0x8f4203b0, 0x24420001, 0xaf4203b0, 0x8f4203b0,
-0x8f820220, 0x2002021, 0x34420002, 0xc004e9c,
-0xaf820220, 0x8f820220, 0x3c0308ff, 0x3463ffff,
-0x431024, 0x511025, 0xaf820220, 0x8fbf0020,
-0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028,
-0x3e00008, 0x0, 0x3c020001, 0x8c426da8,
-0x27bdffb0, 0xafbf0048, 0xafbe0044, 0xafb50040,
-0xafb3003c, 0xafb20038, 0xafb10034, 0x1040000f,
-0xafb00030, 0x3c040001, 0x24846a00, 0x3c050008,
-0xafa00010, 0xafa00014, 0x8f860220, 0x34a50600,
-0x24020001, 0x3c010001, 0xac206da8, 0x3c010001,
-0xac226d9c, 0xc002b3b, 0x3821, 0x3c037fff,
-0x8c020268, 0x3463ffff, 0x3c04fdff, 0x431024,
-0xac020268, 0x8f420004, 0x3484ffff, 0x30420002,
-0x10400092, 0x284a024, 0x3c040600, 0x34842000,
-0x8f420004, 0x2821, 0x2403fffd, 0x431024,
-0xaf420004, 0xafa40020, 0x8f5e0018, 0x27aa0020,
-0x240200ff, 0x13c20002, 0xafaa002c, 0x27c50001,
-0x8c020228, 0xa09021, 0x1642000e, 0x1e38c0,
-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
-0x8c020228, 0x3c040001, 0x24846998, 0x3c050009,
-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d,
-0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
-0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
-0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
-0x9821, 0xe08821, 0x263504c0, 0x8f440178,
-0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010,
-0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
-0xa3482b, 0x822021, 0x100f809, 0x892021,
-0x54400006, 0x24130001, 0x8f820054, 0x2021023,
-0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
-0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
-0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
-0xafa20010, 0x8f820124, 0x3c040001, 0x248469a4,
-0x3c050009, 0xafa20014, 0x8d460000, 0x10000035,
-0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
-0xaf420308, 0x8f420308, 0x1000001e, 0x326200ff,
-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
-0x2c4203e9, 0x10400016, 0x9821, 0x3c150020,
-0x24110010, 0x8f42000c, 0x8f440160, 0x8f450164,
-0x8f860120, 0xafb10010, 0xafb20014, 0x551025,
-0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
-0x24c6001c, 0x1440ffe3, 0x0, 0x8f820054,
-0x2021023, 0x2c4203e9, 0x1440ffee, 0x0,
-0x326200ff, 0x14400011, 0x0, 0x8f420378,
-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
-0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
-0x248469ac, 0x3c050009, 0xafa20014, 0x8d460000,
-0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202ec,
-0x24420001, 0xaf4202ec, 0x8f4202ec, 0x8fbf0048,
-0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038,
-0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050,
-0x3c020001, 0x8c426da8, 0x27bdffe0, 0x1440000d,
-0xafbf0018, 0x3c040001, 0x24846a0c, 0x3c050008,
-0xafa00010, 0xafa00014, 0x8f860220, 0x34a50700,
-0x24020001, 0x3c010001, 0xac226da8, 0xc002b3b,
-0x3821, 0x3c020004, 0x2c21024, 0x10400007,
-0x0, 0x8f820220, 0x3c0308ff, 0x3463ffff,
-0x431024, 0x34420008, 0xaf820220, 0x3c050001,
-0x8ca56d98, 0x24020001, 0x14a20007, 0x2021,
-0xc00529b, 0x24050001, 0xac02026c, 0x8c03026c,
-0x10000006, 0x3c020007, 0xc00529b, 0x2021,
-0xac020268, 0x8c030268, 0x3c020007, 0x621824,
-0x3c020002, 0x5062000d, 0x3c0205f5, 0x43102b,
-0x14400006, 0x3c020004, 0x3c020001, 0x10620009,
-0x3c020098, 0x1000000b, 0x0, 0x14620009,
-0x3c023b9a, 0x10000004, 0x3442ca00, 0x10000002,
-0x3442e100, 0x34429680, 0xaf4201fc, 0x8f4201fc,
-0xaee20064, 0x8fbf0018, 0x3e00008, 0x27bd0020,
-0x0, 0x0, 0x0, 0x86102b,
-0x50400001, 0x872023, 0xc41023, 0x24843,
-0x125102b, 0x1040001b, 0x91040, 0x824021,
-0x88102b, 0x10400007, 0x1821, 0x94820000,
-0x24840002, 0x621821, 0x88102b, 0x1440fffb,
-0x0, 0x602021, 0xc73023, 0xa91023,
-0x21040, 0xc22821, 0xc5102b, 0x10400007,
-0x1821, 0x94c20000, 0x24c60002, 0x621821,
-0xc5102b, 0x1440fffb, 0x0, 0x1000000d,
-0x832021, 0x51040, 0x822821, 0x85102b,
-0x10400007, 0x1821, 0x94820000, 0x24840002,
-0x621821, 0x85102b, 0x1440fffb, 0x0,
-0x602021, 0x41c02, 0x3082ffff, 0x622021,
-0x41c02, 0x3082ffff, 0x622021, 0x3e00008,
-0x3082ffff, 0x3e00008, 0x0, 0x802821,
-0x30a20001, 0x1040002b, 0x3c03001f, 0x3463ffff,
-0x24a20004, 0x62102b, 0x54400007, 0x65102b,
-0x90a20001, 0x90a40003, 0x90a30000, 0x90a50002,
-0x1000002a, 0x441021, 0x10400003, 0x0,
-0x8f420148, 0xa22823, 0x90a40000, 0x24a50001,
-0x65102b, 0x10400003, 0x0, 0x8f420148,
-0xa22823, 0x90a20000, 0x24a50001, 0x21200,
-0x822021, 0x65102b, 0x10400003, 0x0,
-0x8f420148, 0xa22823, 0x90a20000, 0x24a50001,
-0x822021, 0x65102b, 0x10400003, 0x0,
-0x8f420148, 0xa22823, 0x90a20000, 0x1000002d,
-0x21200, 0x3463ffff, 0x24a20004, 0x62102b,
-0x5440000a, 0x65102b, 0x90a20000, 0x90a40002,
-0x90a30001, 0x90a50003, 0x441021, 0x21200,
-0x651821, 0x10000020, 0x432021, 0x10400003,
-0x0, 0x8f420148, 0xa22823, 0x90a20000,
-0x24a50001, 0x22200, 0x65102b, 0x10400003,
-0x0, 0x8f420148, 0xa22823, 0x90a20000,
-0x24a50001, 0x822021, 0x65102b, 0x10400003,
-0x0, 0x8f420148, 0xa22823, 0x90a20000,
-0x24a50001, 0x21200, 0x822021, 0x65102b,
-0x10400003, 0x0, 0x8f420148, 0xa22823,
-0x90a20000, 0x822021, 0x41c02, 0x3082ffff,
-0x622021, 0x41c02, 0x3082ffff, 0x622021,
-0x3e00008, 0x3082ffff, 0x0, 0x8f820220,
-0x34420002, 0xaf820220, 0x3c020002, 0x8c428ff8,
-0x30424000, 0x10400054, 0x24040001, 0x8f820200,
-0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd,
-0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x8f820224, 0x1444004d, 0x42040, 0xc4102b,
-0x1040fff1, 0x0, 0x8f820200, 0x451025,
-0xaf820200, 0x8f820220, 0x34428000, 0xaf820220,
-0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
-0x0, 0x8f820220, 0x3c030004, 0x431024,
-0x1440000f, 0x0, 0x8f820220, 0x3c03ffff,
-0x34637fff, 0x431024, 0xaf820220, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x8f820220, 0x3c030004, 0x431024, 0x1440000d,
-0x0, 0x8f820220, 0x34428000, 0xaf820220,
-0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
-0x0, 0x8f820220, 0x3c030004, 0x431024,
-0x1040001b, 0x1021, 0x8f830220, 0x24020001,
-0x10000015, 0x3c04f700, 0x8f820220, 0x3c04f700,
-0x441025, 0xaf820220, 0x8f820220, 0x2403fffd,
-0x431024, 0xaf820220, 0x8f820220, 0x3c030300,
-0x431024, 0x14400003, 0x0, 0x10000008,
-0x1021, 0x8f820220, 0x34420002, 0xaf820220,
-0x8f830220, 0x24020001, 0x641825, 0xaf830220,
-0x3e00008, 0x0, 0x2021, 0x3c050100,
-0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220,
-0x27625000, 0xaf8200c0, 0x27625000, 0xaf8200c4,
-0x27625000, 0xaf8200c8, 0x27625000, 0xaf8200d0,
-0x27625000, 0xaf8200d4, 0x27625000, 0xaf8200d8,
-0x27623000, 0xaf8200e0, 0x27623000, 0xaf8200e4,
-0x27623000, 0xaf8200e8, 0x27622800, 0xaf8200f0,
-0x27622800, 0xaf8200f4, 0x27622800, 0xaf8200f8,
-0x418c0, 0x24840001, 0x3631021, 0xac453004,
-0x3631021, 0xac403000, 0x28820200, 0x1440fff9,
-0x418c0, 0x2021, 0x418c0, 0x24840001,
-0x3631021, 0xac402804, 0x3631021, 0xac402800,
-0x28820100, 0x1440fff9, 0x418c0, 0xaf80023c,
-0x24030080, 0x24040100, 0xac600000, 0x24630004,
-0x64102b, 0x5440fffd, 0xac600000, 0x8f830040,
-0x3c02f000, 0x621824, 0x3c025000, 0x1062000c,
-0x43102b, 0x14400006, 0x3c026000, 0x3c024000,
-0x10620008, 0x24020800, 0x10000008, 0x0,
-0x10620004, 0x24020800, 0x10000004, 0x0,
-0x24020700, 0x3c010001, 0xac226dac, 0x3e00008,
-0x0, 0x3c020001, 0x8c426dbc, 0x27bdffd0,
-0xafbf002c, 0xafb20028, 0xafb10024, 0xafb00020,
-0x3c010001, 0x10400005, 0xac206d94, 0xc004d9e,
-0x0, 0x3c010001, 0xac206dbc, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
-0x621023, 0x2c420065, 0x1440fffc, 0x0,
-0xc004db9, 0x0, 0x24040001, 0x2821,
-0x27a60018, 0x34028000, 0xc0045be, 0xa7a20018,
-0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
-0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
-0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
-0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
-0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
-0x24040001, 0x3c060001, 0x24c66f24, 0xc00457c,
-0x24050002, 0x8f830054, 0x8f820054, 0x10000002,
-0x24630064, 0x8f820054, 0x621023, 0x2c420065,
-0x1440fffc, 0x24040001, 0x24050003, 0x3c100001,
-0x26106f26, 0xc00457c, 0x2003021, 0x97a60018,
-0x3c070001, 0x94e76f24, 0x3c040001, 0x24846ae0,
-0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100,
-0xc002b3b, 0xafa20010, 0x97a20018, 0x1040004d,
-0x24036040, 0x96020000, 0x3042fff0, 0x1443000c,
-0x24020020, 0x3c030001, 0x94636f24, 0x1462000b,
-0x24027830, 0x24020003, 0x3c010001, 0xac226d94,
-0x24020005, 0x3c010001, 0x1000003f, 0xac226f34,
-0x3c030001, 0x94636f24, 0x24027830, 0x1462000c,
-0x24030010, 0x3c020001, 0x94426f26, 0x3042fff0,
-0x14430007, 0x24020003, 0x3c010001, 0xac226d94,
-0x24020006, 0x3c010001, 0x1000002f, 0xac226f34,
-0x3c020001, 0x8c426d94, 0x3c030001, 0x94636f24,
-0x34420001, 0x3c010001, 0xac226d94, 0x24020015,
-0x1462000b, 0x0, 0x3c020001, 0x94426f26,
-0x3042fff0, 0x3843f420, 0x2c630001, 0x3842f430,
-0x2c420001, 0x621825, 0x1460001b, 0x24020003,
-0x3c030001, 0x94636f24, 0x24027810, 0x14620016,
-0x24020002, 0x3c020001, 0x94426f26, 0x3042fff0,
-0x14400011, 0x24020002, 0x1000000f, 0x24020004,
-0x3c020001, 0x8c426d94, 0x34420008, 0x3c010001,
-0xac226d94, 0x1000005e, 0x24020004, 0x3c020001,
-0x8c426d94, 0x34420004, 0x3c010001, 0x100000af,
-0xac226d94, 0x24020001, 0x3c010001, 0xac226f40,
-0x3c020001, 0x8c426d94, 0x30420002, 0x144000b2,
-0x3c09fff0, 0x24020e00, 0xaf820238, 0x8f840054,
-0x8f820054, 0x24030008, 0x3c010001, 0xac236d98,
-0x10000002, 0x248401f4, 0x8f820054, 0x821023,
-0x2c4201f5, 0x1440fffc, 0x3c0200c8, 0x344201fb,
-0xaf820238, 0x8f830054, 0x8f820054, 0x10000002,
-0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5,
-0x1440fffc, 0x8021, 0x24120001, 0x24110009,
-0xc004482, 0x0, 0x3c010001, 0xac326db4,
-0xc004547, 0x0, 0x3c020001, 0x8c426db4,
-0x1451fffb, 0x3c0200c8, 0x344201f6, 0xaf820238,
-0x8f830054, 0x8f820054, 0x10000002, 0x2463000a,
-0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc,
-0x0, 0x8f820220, 0x24040001, 0x34420002,
-0xaf820220, 0x8f830200, 0x24057fff, 0x2402fffd,
-0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x8f820224, 0x14440005, 0x34028000, 0x42040,
-0xa4102b, 0x1040fff0, 0x34028000, 0x1082ffa0,
-0x26100001, 0x2e020014, 0x1440ffcd, 0x24020004,
-0x3c010001, 0xac226d98, 0x8021, 0x24120009,
-0x3c11ffff, 0x36313f7f, 0xc004482, 0x0,
-0x24020001, 0x3c010001, 0xac226db4, 0xc004547,
-0x0, 0x3c020001, 0x8c426db4, 0x1452fffb,
-0x0, 0x8f820044, 0x511024, 0x34425080,
-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
-0x2463000a, 0x8f820054, 0x621023, 0x2c42000b,
-0x1440fffc, 0x0, 0x8f820044, 0x511024,
-0x3442f080, 0xaf820044, 0x8f830054, 0x8f820054,
-0x10000002, 0x2463000a, 0x8f820054, 0x621023,
-0x2c42000b, 0x1440fffc, 0x0, 0x8f820220,
-0x3c03f700, 0x431025, 0xaf820220, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
-0x621023, 0x2c420065, 0x1440fffc, 0x0,
-0x8f820220, 0x24040001, 0x34420002, 0xaf820220,
-0x8f830200, 0x24057fff, 0x2402fffd, 0x621824,
-0xaf830200, 0xaf840204, 0x8f830054, 0x8f820054,
-0x10000002, 0x24630001, 0x8f820054, 0x621023,
-0x2c420002, 0x1440fffc, 0x0, 0x8f820224,
-0x14440005, 0x34028000, 0x42040, 0xa4102b,
-0x1040fff0, 0x34028000, 0x1082ff50, 0x26100001,
-0x2e020064, 0x1440ffb0, 0x0, 0x3c020001,
-0x8c426d94, 0x30420004, 0x14400007, 0x3c09fff0,
-0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024,
-0xaf820044, 0x3c09fff0, 0x3529bdc0, 0x3c060001,
-0x8cc66d94, 0x3c040001, 0x24846ae0, 0x24020001,
-0x3c010001, 0xac226d9c, 0x8f820054, 0x3c070001,
-0x8ce76f40, 0x3c030001, 0x94636f24, 0x3c080001,
-0x95086f26, 0x3c05000d, 0x34a50100, 0x3c010001,
-0xac206d98, 0x491021, 0x3c010001, 0xac226f30,
-0xafa30010, 0xc002b3b, 0xafa80014, 0x8fbf002c,
-0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
-0x27bd0030, 0x27bdffe8, 0x3c050001, 0x8ca56d98,
-0x24060004, 0x24020001, 0x14a20014, 0xafbf0010,
-0x3c020002, 0x8c428ffc, 0x30428000, 0x10400005,
-0x3c04000f, 0x3c030001, 0x8c636f40, 0x10000005,
-0x34844240, 0x3c040004, 0x3c030001, 0x8c636f40,
-0x348493e0, 0x24020005, 0x14620016, 0x0,
-0x3c04003d, 0x10000013, 0x34840900, 0x3c020002,
-0x8c428ff8, 0x30428000, 0x10400005, 0x3c04001e,
-0x3c030001, 0x8c636f40, 0x10000005, 0x34848480,
-0x3c04000f, 0x3c030001, 0x8c636f40, 0x34844240,
-0x24020005, 0x14620003, 0x0, 0x3c04007a,
-0x34841200, 0x3c020001, 0x8c426f30, 0x8f830054,
-0x441021, 0x431023, 0x44102b, 0x1440004c,
-0x0, 0x3c020001, 0x8c426da0, 0x14400048,
-0x0, 0x3c010001, 0x10c00025, 0xac206db0,
-0x3c090001, 0x8d296d94, 0x24070001, 0x3c044000,
-0x3c080002, 0x25088ffc, 0x250afffc, 0x52842,
-0x14a00002, 0x24c6ffff, 0x24050008, 0xa91024,
-0x10400010, 0x0, 0x14a70008, 0x0,
-0x8d020000, 0x441024, 0x1040000a, 0x0,
-0x3c010001, 0x10000007, 0xac256db0, 0x8d420000,
-0x441024, 0x10400003, 0x0, 0x3c010001,
-0xac276db0, 0x3c020001, 0x8c426db0, 0x6182b,
-0x2c420001, 0x431024, 0x5440ffe5, 0x52842,
-0x8f820054, 0x3c030001, 0x8c636db0, 0x3c010001,
-0xac226f30, 0x1060003b, 0x24020005, 0x3c030001,
-0x8c636f40, 0x3c010001, 0xac256d98, 0x14620012,
-0x24020001, 0x3c020002, 0x8c428ff8, 0x3c032000,
-0x34635000, 0x431024, 0x14400006, 0x24020001,
-0x3c010001, 0xac206f1c, 0x3c010001, 0xac226d98,
-0x24020001, 0x3c010001, 0xac226e24, 0x3c010001,
-0xac226da4, 0x24020001, 0x3c010001, 0xac226d9c,
-0x3c020001, 0x8c426db0, 0x1040001e, 0x0,
-0x3c020001, 0x8c426d9c, 0x10400008, 0x24020001,
-0x3c010001, 0xac206d9c, 0xaee204b8, 0x3c010001,
-0xac206e1c, 0x3c010001, 0xac226dd4, 0x8ee304b8,
-0x24020008, 0x10620005, 0x24020001, 0xc004239,
-0x0, 0x1000000b, 0x0, 0x3c030001,
-0x8c636d98, 0x10620007, 0x2402000e, 0x3c030002,
-0x8c638f90, 0x10620003, 0x0, 0xc004e9c,
-0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018,
-0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c846d98,
-0x3c020001, 0x8c426dc0, 0x3463ffff, 0x283a024,
-0x14820006, 0xafbf0018, 0x8ee304b8, 0x3c020001,
-0x8c426dc4, 0x10620006, 0x0, 0x8ee204b8,
-0x3c010001, 0xac246dc0, 0x3c010001, 0xac226dc4,
-0x3c030001, 0x8c636d98, 0x24020002, 0x1062019c,
-0x2c620003, 0x10400005, 0x24020001, 0x1062000a,
-0x0, 0x10000226, 0x0, 0x24020004,
-0x106200b6, 0x24020008, 0x1062010a, 0x24020001,
-0x1000021f, 0x0, 0x8ee204b8, 0x2443ffff,
-0x2c620008, 0x1040021c, 0x31080, 0x3c010001,
-0x220821, 0x8c226af8, 0x400008, 0x0,
-0x3c030001, 0x8c636f40, 0x24020005, 0x14620010,
-0x0, 0x3c020001, 0x8c426da4, 0x10400008,
-0x24020003, 0xc004482, 0x0, 0x24020002,
-0xaee204b8, 0x3c010001, 0x10000002, 0xac206da4,
-0xaee204b8, 0x3c010001, 0x10000203, 0xac206d30,
-0xc004482, 0x0, 0x3c020001, 0x8c426da4,
-0x3c010001, 0xac206d30, 0x1440017a, 0x24020002,
-0x1000019d, 0x24020007, 0x3c030001, 0x8c636f40,
-0x24020005, 0x14620003, 0x24020001, 0x3c010001,
-0xac226dd0, 0xc0045ff, 0x0, 0x3c030001,
-0x8c636dd0, 0x10000174, 0x24020011, 0x3c050001,
-0x8ca56d98, 0x3c060002, 0x8cc68ffc, 0xc005104,
-0x2021, 0x24020005, 0x3c010001, 0xac206da4,
-0x100001e1, 0xaee204b8, 0x3c040001, 0x24846aec,
-0x3c05000f, 0x34a50100, 0x3021, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x100001d6,
-0x0, 0x8f820220, 0x3c030004, 0x431024,
-0x14400175, 0x24020007, 0x8f830054, 0x3c020001,
-0x8c426f28, 0x2463d8f0, 0x431023, 0x2c422710,
-0x14400003, 0x24020001, 0x3c010001, 0xac226d9c,
-0x3c020002, 0x8c428ffc, 0x30425000, 0x104001c2,
-0x0, 0x8f820220, 0x30428000, 0x1040017d,
-0x0, 0x10000175, 0x0, 0x3c050001,
-0x8ca56d98, 0xc00529b, 0x2021, 0xc00551b,
-0x2021, 0x3c030002, 0x8c638ff4, 0x46101b0,
-0x24020001, 0x3c020008, 0x621024, 0x10400006,
-0x0, 0x8f820214, 0x3c03ffff, 0x431024,
-0x10000005, 0x3442251f, 0x8f820214, 0x3c03ffff,
-0x431024, 0x3442241f, 0xaf820214, 0x8f820220,
-0x3c030200, 0x34420002, 0xaf820220, 0x24020008,
-0xaee204b8, 0x8f820220, 0x283a025, 0x3c030004,
-0x431024, 0x14400016, 0x0, 0x3c020002,
-0x8c428ffc, 0x30425000, 0x1040000d, 0x0,
-0x8f820220, 0x30428000, 0x10400006, 0x0,
-0x8f820220, 0x3c03ffff, 0x34637fff, 0x10000003,
-0x431024, 0x8f820220, 0x34428000, 0xaf820220,
-0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
-0x3c030001, 0x8c636f40, 0x24020005, 0x1462000a,
-0x0, 0x3c020001, 0x94426f26, 0x24429fbc,
-0x2c420004, 0x10400004, 0x24040018, 0x24050002,
-0xc004ddb, 0x24060020, 0xc003e6d, 0x0,
-0x3c010001, 0x10000170, 0xac206e20, 0x8ee204b8,
-0x2443ffff, 0x2c620008, 0x1040016b, 0x31080,
-0x3c010001, 0x220821, 0x8c226b18, 0x400008,
-0x0, 0xc004547, 0x0, 0x3c030001,
-0x8c636db4, 0x100000e8, 0x24020009, 0x3c020002,
-0x8c428ff8, 0x30424000, 0x10400004, 0x0,
-0x8f820044, 0x10000006, 0x3442f080, 0x8f820044,
-0x3c03ffff, 0x34633f7f, 0x431024, 0x3442a080,
-0xaf820044, 0x8f830054, 0x100000ea, 0x24020004,
-0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0,
-0x431023, 0x2c422710, 0x14400147, 0x24020005,
-0x100000d8, 0x0, 0x8f820220, 0x3c03f700,
-0x431025, 0xaf820220, 0xaf800204, 0x3c010002,
-0x100000d6, 0xac208fe0, 0x8f830054, 0x3c020001,
-0x8c426f28, 0x2463fff6, 0x431023, 0x2c42000a,
-0x14400135, 0x24020007, 0x100000d7, 0x0,
-0xc003f50, 0x0, 0x1040012d, 0x24020001,
-0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c846f1c,
-0x431024, 0x3442251f, 0xaf820214, 0x24020008,
-0x10800005, 0xaee204b8, 0x3c020001, 0x8c426e44,
-0x10400064, 0x24020001, 0x8f820220, 0x3c030008,
-0x431024, 0x1040006a, 0x3c020200, 0x10000078,
-0x0, 0x8ee204b8, 0x2443ffff, 0x2c620007,
-0x10400115, 0x31080, 0x3c010001, 0x220821,
-0x8c226b38, 0x400008, 0x0, 0xc003daf,
-0x0, 0x3c010001, 0xac206d9c, 0xaf800204,
-0x3c010002, 0xc004482, 0xac208fe0, 0x24020001,
-0x3c010001, 0xac226db4, 0x24020002, 0x10000102,
-0xaee204b8, 0xc004547, 0x0, 0x3c030001,
-0x8c636db4, 0x10000084, 0x24020009, 0x3c020002,
-0x8c428ff8, 0x30424000, 0x10400003, 0x3c0200c8,
-0x10000002, 0x344201f6, 0x344201fe, 0xaf820238,
-0x8f830054, 0x1000008b, 0x24020004, 0x8f830054,
-0x3c020001, 0x8c426f28, 0x2463d8f0, 0x431023,
-0x2c422710, 0x144000e8, 0x24020005, 0x10000079,
-0x0, 0x8f820220, 0x3c03f700, 0x431025,
-0xaf820220, 0xaf800204, 0x3c010002, 0x10000077,
-0xac208fe0, 0x8f830054, 0x3c020001, 0x8c426f28,
-0x2463fff6, 0x431023, 0x2c42000a, 0x144000d6,
-0x24020007, 0x10000078, 0x0, 0xc003f50,
-0x0, 0x104000ce, 0x24020001, 0x8f820214,
-0x3c03ffff, 0x3c040001, 0x8c846f1c, 0x431024,
-0x3442251f, 0xaf820214, 0x24020008, 0x1080000f,
-0xaee204b8, 0x3c020001, 0x8c426e44, 0x1440000b,
-0x0, 0x8f820220, 0x34420002, 0xaf820220,
-0x24020001, 0x3c010002, 0xac228f90, 0xc004e9c,
-0x8f840220, 0x10000016, 0x0, 0x8f820220,
-0x3c030008, 0x431024, 0x14400011, 0x3c020200,
-0x282a025, 0x2402000e, 0x3c010002, 0xac228f90,
-0xc00551b, 0x2021, 0x8f820220, 0x34420002,
-0xc003e6d, 0xaf820220, 0x3c050001, 0x8ca56d98,
-0xc00529b, 0x2021, 0x100000a3, 0x0,
-0x3c020001, 0x8c426e44, 0x1040009f, 0x0,
-0x3c020001, 0x8c426e40, 0x2442ffff, 0x3c010001,
-0xac226e40, 0x14400098, 0x24020002, 0x3c010001,
-0xac206e44, 0x3c010001, 0x10000093, 0xac226e40,
-0x8ee204b8, 0x2443ffff, 0x2c620007, 0x1040008e,
-0x31080, 0x3c010001, 0x220821, 0x8c226b58,
-0x400008, 0x0, 0x3c020001, 0x8c426da4,
-0x10400018, 0x24020005, 0xc004482, 0x0,
-0x24020002, 0xaee204b8, 0x3c010001, 0x1000007e,
-0xac206da4, 0xc004963, 0x0, 0x3c030001,
-0x8c636dd4, 0x24020006, 0x14620077, 0x24020003,
-0x10000075, 0xaee204b8, 0x3c050001, 0x8ca56d98,
-0x3c060002, 0x8cc68ff8, 0xc005104, 0x2021,
-0x24020005, 0x1000006c, 0xaee204b8, 0x8f820220,
-0x3c03f700, 0x431025, 0xaf820220, 0x8f830054,
-0x24020006, 0xaee204b8, 0x3c010001, 0x10000062,
-0xac236f28, 0x8f820220, 0x3c030004, 0x431024,
-0x10400003, 0x24020007, 0x1000005b, 0xaee204b8,
-0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0,
-0x431023, 0x2c422710, 0x14400003, 0x24020001,
-0x3c010001, 0xac226d9c, 0x3c020002, 0x8c428ff8,
-0x30425000, 0x1040004c, 0x0, 0x8f820220,
-0x30428000, 0x10400007, 0x0, 0x8f820220,
-0x3c03ffff, 0x34637fff, 0x431024, 0x10000042,
-0xaf820220, 0x8f820220, 0x34428000, 0x1000003e,
-0xaf820220, 0x3c050001, 0x8ca56d98, 0xc00529b,
-0x2021, 0xc00551b, 0x2021, 0x3c020002,
-0x8c428ff0, 0x4410032, 0x24020001, 0x8f820214,
-0x3c03ffff, 0x431024, 0x3442251f, 0xaf820214,
-0x24020008, 0xaee204b8, 0x8f820220, 0x34420002,
-0xaf820220, 0x8f820220, 0x3c030004, 0x431024,
-0x14400016, 0x0, 0x3c020002, 0x8c428ff8,
-0x30425000, 0x1040000d, 0x0, 0x8f820220,
-0x30428000, 0x10400006, 0x0, 0x8f820220,
-0x3c03ffff, 0x34637fff, 0x10000003, 0x431024,
-0x8f820220, 0x34428000, 0xaf820220, 0x8f820220,
-0x3c03f700, 0x431025, 0xaf820220, 0x3c020001,
-0x94426f26, 0x24429fbc, 0x2c420004, 0x10400004,
-0x24040018, 0x24050002, 0xc004ddb, 0x24060020,
-0xc003e6d, 0x0, 0x10000003, 0x0,
-0x3c010001, 0xac226d9c, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220,
-0x34420004, 0xaf820220, 0x8f820200, 0x3c050001,
-0x8ca56d98, 0x34420004, 0xaf820200, 0x24020002,
-0x10a2004b, 0x2ca20003, 0x10400005, 0x24020001,
-0x10a2000a, 0x0, 0x100000b1, 0x0,
-0x24020004, 0x10a20072, 0x24020008, 0x10a20085,
-0x3c02f0ff, 0x100000aa, 0x0, 0x8f830050,
-0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c846f40,
-0x621824, 0x3c020700, 0x621825, 0x24020e00,
-0x2484fffb, 0x2c840002, 0xaf830050, 0xaf850200,
-0xaf850220, 0x14800006, 0xaf820238, 0x8f820044,
-0x3c03ffff, 0x34633f7f, 0x431024, 0xaf820044,
-0x3c030001, 0x8c636f40, 0x24020005, 0x14620004,
-0x0, 0x8f820044, 0x34425000, 0xaf820044,
-0x3c020001, 0x8c426d88, 0x3c030001, 0x8c636f40,
-0x34420022, 0x2463fffc, 0x2c630002, 0x1460000c,
-0xaf820200, 0x3c020001, 0x8c426dac, 0x3c030001,
-0x8c636d90, 0x3c040001, 0x8c846d8c, 0x34428000,
-0x621825, 0x641825, 0x1000000a, 0x34620002,
-0x3c020001, 0x8c426d90, 0x3c030001, 0x8c636dac,
-0x3c040001, 0x8c846d8c, 0x431025, 0x441025,
-0x34420002, 0xaf820220, 0x1000002f, 0x24020001,
-0x24020e01, 0xaf820238, 0x8f830050, 0x3c02f0ff,
-0x3442ffff, 0x3c040001, 0x8c846f1c, 0x621824,
-0x3c020d00, 0x621825, 0x24020001, 0xaf830050,
-0xaf820200, 0xaf820220, 0x10800005, 0x3c033f00,
-0x3c020001, 0x8c426d80, 0x10000004, 0x34630070,
-0x3c020001, 0x8c426d80, 0x34630072, 0x431025,
-0xaf820200, 0x3c030001, 0x8c636d84, 0x3c02f700,
-0x621825, 0x3c020001, 0x8c426d90, 0x3c040001,
-0x8c846dac, 0x3c050001, 0x8ca56f40, 0x431025,
-0x441025, 0xaf820220, 0x24020005, 0x14a20006,
-0x24020001, 0x8f820044, 0x2403afff, 0x431024,
-0xaf820044, 0x24020001, 0x1000003d, 0xaf820238,
-0x8f830050, 0x3c02f0ff, 0x3442ffff, 0x3c040001,
-0x8c846f1c, 0x621824, 0x3c020a00, 0x621825,
-0x24020001, 0xaf830050, 0xaf820200, 0x1080001e,
-0xaf820220, 0x3c020001, 0x8c426e44, 0x1440001a,
-0x3c033f00, 0x3c020001, 0x8c426d80, 0x1000001a,
-0x346300e0, 0x8f830050, 0x3c040001, 0x8c846f1c,
-0x3442ffff, 0x621824, 0x1080000f, 0xaf830050,
-0x3c020001, 0x8c426e44, 0x1440000b, 0x3c043f00,
-0x3c030001, 0x8c636d80, 0x348400e0, 0x24020001,
-0xaf820200, 0xaf820220, 0x641825, 0xaf830200,
-0x10000008, 0x3c05f700, 0x3c020001, 0x8c426d80,
-0x3c033f00, 0x346300e2, 0x431025, 0xaf820200,
-0x3c05f700, 0x34a58000, 0x3c030001, 0x8c636d84,
-0x3c020001, 0x8c426d90, 0x3c040001, 0x8c846dac,
-0x651825, 0x431025, 0x441025, 0xaf820220,
-0x3e00008, 0x0, 0x3c030001, 0x8c636db4,
-0x3c020001, 0x8c426db8, 0x10620003, 0x24020002,
-0x3c010001, 0xac236db8, 0x1062001d, 0x2c620003,
-0x10400025, 0x24020001, 0x14620023, 0x24020004,
-0x3c030001, 0x8c636d98, 0x10620006, 0x24020008,
-0x1462000c, 0x3c0200c8, 0x344201fb, 0x10000009,
-0xaf820238, 0x24020e01, 0xaf820238, 0x8f820044,
-0x3c03ffff, 0x34633f7f, 0x431024, 0x34420080,
-0xaf820044, 0x8f830054, 0x24020002, 0x3c010001,
-0xac226db4, 0x3c010001, 0x1000000b, 0xac236f2c,
-0x8f830054, 0x3c020001, 0x8c426f2c, 0x2463d8f0,
-0x431023, 0x2c422710, 0x14400003, 0x24020009,
-0x3c010001, 0xac226db4, 0x3e00008, 0x0,
-0x0, 0x0, 0x0, 0x27bdffd8,
-0xafb20018, 0x809021, 0xafb3001c, 0xa09821,
-0xafb10014, 0xc08821, 0xafb00010, 0x8021,
-0xafbf0020, 0xa6200000, 0xc004d78, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x24100010, 0x2501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x2501024, 0x24100010, 0x2701024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x2701024, 0xc004db9, 0x34108000,
-0xc004db9, 0x0, 0xc004d58, 0x0,
-0x50400005, 0x108042, 0x96220000, 0x501025,
-0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004db9, 0x0, 0x8fbf0020, 0x8fb3001c,
-0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008,
-0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821,
-0xafb20018, 0xa09021, 0xafb3001c, 0xc09821,
-0xafb00010, 0x8021, 0xafbf0020, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0x24100010, 0x2301024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x2301024, 0x24100010, 0x2501024,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x2501024, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x34108000,
-0x96620000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
-0x0, 0xc004db9, 0x0, 0x8fbf0020,
-0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
-0x3e00008, 0x27bd0028, 0x3c040001, 0x8c846dd0,
-0x3c020001, 0x8c426e18, 0x27bdffd8, 0xafbf0020,
-0xafb1001c, 0x10820003, 0xafb00018, 0x3c010001,
-0xac246e18, 0x3c030001, 0x8c636f40, 0x24020005,
-0x14620005, 0x2483ffff, 0xc004963, 0x0,
-0x1000034c, 0x0, 0x2c620013, 0x10400349,
-0x31080, 0x3c010001, 0x220821, 0x8c226b80,
-0x400008, 0x0, 0xc004db9, 0x8021,
-0x34028000, 0xa7a20010, 0x27b10010, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0xc004d78,
-0x2021, 0x108042, 0x1600fffc, 0x0,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x1000030e, 0x24020002, 0x27b10010, 0xa7a00010,
-0x8021, 0xc004d78, 0x24040001, 0x26100001,
-0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
-0x2021, 0xc004d78, 0x24040001, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x24100010,
-0x32020001, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
-0x24100010, 0xc004d78, 0x2021, 0x108042,
-0x1600fffc, 0x0, 0xc004db9, 0x34108000,
-0xc004db9, 0x0, 0xc004d58, 0x0,
-0x50400005, 0x108042, 0x96220000, 0x501025,
-0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004db9, 0x0, 0x97a20010, 0x30428000,
-0x144002dc, 0x24020003, 0x100002d8, 0x0,
-0x24021200, 0xa7a20010, 0x27b10010, 0x8021,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0xc004d78, 0x2021, 0x108042, 0x1600fffc,
-0x0, 0xc004d78, 0x24040001, 0xc004d78,
-0x2021, 0x34108000, 0x96220000, 0x501024,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fff8, 0x0, 0xc004db9,
-0x0, 0x8f830054, 0x10000296, 0x24020004,
-0x8f830054, 0x3c020001, 0x8c426f3c, 0x2463ff9c,
-0x431023, 0x2c420064, 0x1440029e, 0x24020002,
-0x3c030001, 0x8c636f40, 0x10620297, 0x2c620003,
-0x14400296, 0x24020011, 0x24020003, 0x10620005,
-0x24020004, 0x10620291, 0x2402000f, 0x1000028f,
-0x24020011, 0x1000028d, 0x24020005, 0x24020014,
-0xa7a20010, 0x27b10010, 0x8021, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x32020012,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020012, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x34108000,
-0x96220000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
-0x0, 0xc004db9, 0x0, 0x8f830054,
-0x10000248, 0x24020006, 0x8f830054, 0x3c020001,
-0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064,
-0x14400250, 0x24020007, 0x1000024c, 0x0,
-0x24020006, 0xa7a20010, 0x27b10010, 0x8021,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020013, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020013,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x8f830054, 0x10000207, 0x24020008, 0x8f830054,
-0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
-0x2c420064, 0x1440020f, 0x24020009, 0x1000020b,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x8021,
-0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x8f830054, 0x10000193, 0x2402000a, 0x8f830054,
-0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
-0x2c420064, 0x1440019b, 0x2402000b, 0x10000197,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020017, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020017,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x8021,
-0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020017, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020017,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054,
-0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
-0x2c420064, 0x14400127, 0x24020012, 0x10000123,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020014, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020014,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x8021,
-0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020014, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020014,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x8f830054, 0x100000ab, 0x24020013, 0x8f830054,
-0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
-0x2c420064, 0x144000b3, 0x2402000d, 0x100000af,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x8021,
-0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x8f830054, 0x10000037, 0x2402000e, 0x24020840,
-0xa7a20010, 0x27b10010, 0x8021, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x32020013,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020013, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x34108000,
-0x96220000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
-0x0, 0xc004db9, 0x0, 0x8f830054,
-0x24020010, 0x3c010001, 0xac226dd0, 0x3c010001,
-0x1000000c, 0xac236f3c, 0x8f830054, 0x3c020001,
-0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064,
-0x14400004, 0x0, 0x24020011, 0x3c010001,
-0xac226dd0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
-0x3e00008, 0x27bd0028, 0x3c030001, 0x8c636d98,
-0x27bdffc8, 0x24020002, 0xafbf0034, 0xafb20030,
-0xafb1002c, 0x14620004, 0xafb00028, 0x3c120002,
-0x10000003, 0x8e528ff8, 0x3c120002, 0x8e528ffc,
-0x3c030001, 0x8c636dd4, 0x3c020001, 0x8c426e1c,
-0x50620004, 0x2463ffff, 0x3c010001, 0xac236e1c,
-0x2463ffff, 0x2c620006, 0x10400377, 0x31080,
-0x3c010001, 0x220821, 0x8c226bd8, 0x400008,
-0x0, 0x2021, 0x2821, 0xc004ddb,
-0x34068000, 0x24040010, 0x24050002, 0x24060002,
-0x24020002, 0xc004ddb, 0xa7a20018, 0x24020002,
-0x3c010001, 0x10000364, 0xac226dd4, 0x27b10018,
-0xa7a00018, 0x8021, 0xc004d78, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x24100010, 0x32020001, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x32020001, 0x24100010, 0xc004d78, 0x2021,
-0x108042, 0x1600fffc, 0x0, 0xc004db9,
-0x34108000, 0xc004db9, 0x0, 0xc004d58,
-0x0, 0x50400005, 0x108042, 0x96220000,
-0x501025, 0xa6220000, 0x108042, 0x1600fff7,
-0x0, 0xc004db9, 0x0, 0x97a20018,
-0x30428000, 0x14400004, 0x24020003, 0x3c010001,
-0xac226dd4, 0x24020003, 0x3c010001, 0x1000032a,
-0xac226dd4, 0x24040010, 0x24050002, 0x24060002,
-0x24020002, 0xc004ddb, 0xa7a20018, 0x3c030001,
-0x8c636e20, 0x24020001, 0x146201e1, 0x8021,
-0x27b10018, 0xa7a00018, 0xc004d78, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x24100010, 0x32020001, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x32020001, 0x24100010, 0x32020018, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020018, 0xc004db9, 0x34108000,
-0xc004db9, 0x0, 0xc004d58, 0x0,
-0x50400005, 0x108042, 0x96220000, 0x501025,
-0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004db9, 0x8021, 0x27b10018, 0xa7a00018,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x8021,
-0x24040018, 0x2821, 0xc004ddb, 0x24060404,
-0xa7a0001a, 0xc004d78, 0x24040001, 0x26100001,
-0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
-0x2021, 0xc004d78, 0x24040001, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x24100010,
-0x32020001, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
-0x24100010, 0x32020018, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x32020018, 0xc004db9, 0x34108000, 0xc004db9,
-0x0, 0xc004d58, 0x0, 0x50400005,
-0x108042, 0x97a2001a, 0x501025, 0xa7a2001a,
-0x108042, 0x1600fff7, 0x0, 0xc004db9,
-0x8021, 0xa7a0001a, 0xc004d78, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x24100010, 0x32020001, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x32020001, 0x24100010, 0x32020018, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020018, 0xc004db9, 0x34108000,
-0xc004db9, 0x0, 0xc004d58, 0x0,
-0x50400005, 0x108042, 0x97a2001a, 0x501025,
-0xa7a2001a, 0x108042, 0x1600fff7, 0x0,
-0xc004db9, 0x8021, 0xa7a0001c, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
-0x2021, 0x24100010, 0xc004d78, 0x2021,
-0x108042, 0x1600fffc, 0x0, 0x24100010,
-0x3202001e, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x3202001e,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x97a2001c, 0x501025, 0xa7a2001c, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x8021,
-0xa7a0001c, 0xc004d78, 0x24040001, 0x26100001,
-0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
-0x2021, 0xc004d78, 0x24040001, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x24100010,
-0xc004d78, 0x2021, 0x108042, 0x1600fffc,
-0x0, 0x24100010, 0x3202001e, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x3202001e, 0xc004db9, 0x34108000,
-0xc004db9, 0x0, 0xc004d58, 0x0,
-0x50400005, 0x108042, 0x97a2001c, 0x501025,
-0xa7a2001c, 0x108042, 0x1600fff7, 0x0,
-0xc004db9, 0x8021, 0x24020002, 0xa7a2001e,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0xc004d78,
-0x2021, 0x108042, 0x1600fffc, 0x0,
-0x24100010, 0x3202001e, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x3202001e, 0xc004d78, 0x24040001, 0xc004d78,
-0x2021, 0x34108000, 0x97a2001e, 0x501024,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fff8, 0x0, 0xc004db9,
-0x8021, 0xa7a00020, 0xc004d78, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x24100010, 0xc004d78, 0x2021, 0x108042,
-0x1600fffc, 0x0, 0x24100010, 0x3202001e,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x3202001e, 0xc004db9,
-0x34108000, 0xc004db9, 0x0, 0xc004d58,
-0x0, 0x50400005, 0x108042, 0x97a20020,
-0x501025, 0xa7a20020, 0x108042, 0x1600fff7,
-0x0, 0xc004db9, 0x8021, 0xa7a00020,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0x24100010, 0xc004d78,
-0x2021, 0x108042, 0x1600fffc, 0x0,
-0x24100010, 0x3202001e, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x3202001e, 0xc004db9, 0x34108000, 0xc004db9,
-0x0, 0xc004d58, 0x0, 0x50400005,
-0x108042, 0x97a20020, 0x501025, 0xa7a20020,
-0x108042, 0x1600fff7, 0x0, 0xc004db9,
-0x8021, 0xa7a00022, 0xc004d78, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0x24100010, 0xc004d78, 0x2021, 0x108042,
-0x1600fffc, 0x0, 0x24100010, 0xc004d78,
-0x2021, 0x108042, 0x1600fffc, 0x0,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x97a20022, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x24040018, 0x24050002, 0xc004ddb, 0x24060004,
-0x3c100001, 0x8e106e24, 0x24020001, 0x1602011d,
-0x0, 0x3c020001, 0x94426f26, 0x3c010001,
-0xac206e24, 0x24429fbc, 0x2c420004, 0x1040000c,
-0x24040009, 0x24050001, 0xc004ddb, 0x24060400,
-0x24040018, 0x24050001, 0xc004ddb, 0x24060020,
-0x24040018, 0x24050001, 0xc004ddb, 0x24062000,
-0x3c024000, 0x2421024, 0x10400123, 0x3c022000,
-0x2421024, 0x10400004, 0x0, 0x3c010001,
-0x10000003, 0xac306f1c, 0x3c010001, 0xac206f1c,
-0x3c030001, 0x8c636f34, 0x24020005, 0x146200f9,
-0x0, 0x3c020001, 0x8c426f1c, 0x10400067,
-0x3c020004, 0x2421024, 0x10400011, 0xa7a00018,
-0x3c020008, 0x2421024, 0x10400002, 0x24020200,
-0xa7a20018, 0x3c020010, 0x2421024, 0x10400004,
-0x0, 0x97a20018, 0x34420100, 0xa7a20018,
-0x97a60018, 0x24040009, 0x10000004, 0x2821,
-0x24040009, 0x2821, 0x3021, 0xc004ddb,
-0x0, 0x24020001, 0xa7a2001a, 0x3c020008,
-0x2421024, 0x1040000c, 0x3c020002, 0x2421024,
-0x10400002, 0x24020101, 0xa7a2001a, 0x3c020001,
-0x2421024, 0x10400005, 0x3c020010, 0x97a2001a,
-0x34420040, 0xa7a2001a, 0x3c020010, 0x2421024,
-0x1040000e, 0x3c020002, 0x2421024, 0x10400005,
-0x3c020001, 0x97a2001a, 0x34420080, 0xa7a2001a,
-0x3c020001, 0x2421024, 0x10400005, 0x3c0300a0,
-0x97a2001a, 0x34420020, 0xa7a2001a, 0x3c0300a0,
-0x2431024, 0x54430004, 0x3c020020, 0x97a2001a,
-0x1000000c, 0x34420400, 0x2421024, 0x50400004,
-0x3c020080, 0x97a2001a, 0x10000006, 0x34420800,
-0x2421024, 0x10400004, 0x0, 0x97a2001a,
-0x34420c00, 0xa7a2001a, 0x97a6001a, 0x24040004,
-0xc004ddb, 0x2821, 0x3c020004, 0x2421024,
-0x10400004, 0xa7a0001c, 0x32425000, 0x14400004,
-0x0, 0x32424000, 0x10400005, 0x2021,
-0xc004cf9, 0x2402021, 0x10000096, 0x0,
-0x97a6001c, 0x2821, 0x34c61200, 0xc004ddb,
-0xa7a6001c, 0x1000008f, 0x0, 0x2421024,
-0x10400004, 0xa7a00018, 0x32425000, 0x14400004,
-0x0, 0x32424000, 0x10400005, 0x3c020010,
-0xc004cf9, 0x2402021, 0x10000019, 0xa7a0001a,
-0x2421024, 0x10400004, 0x0, 0x97a20018,
-0x10000004, 0xa7a20018, 0x97a20018, 0x34420100,
-0xa7a20018, 0x3c020001, 0x2421024, 0x10400004,
-0x0, 0x97a20018, 0x10000004, 0xa7a20018,
-0x97a20018, 0x34422000, 0xa7a20018, 0x97a60018,
-0x2021, 0xc004ddb, 0x2821, 0xa7a0001a,
-0x8021, 0xc004d78, 0x24040001, 0x26100001,
-0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
-0x2021, 0xc004d78, 0x24040001, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x24100010,
-0x32020001, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
-0x24100010, 0xc004d78, 0x2021, 0x108042,
-0x1600fffc, 0x0, 0xc004db9, 0x34108000,
-0xc004db9, 0x0, 0xc004d58, 0x0,
-0x50400005, 0x108042, 0x97a2001a, 0x501025,
-0xa7a2001a, 0x108042, 0x1600fff7, 0x0,
-0xc004db9, 0x8021, 0xa7a0001a, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
-0x2021, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0xc004d78,
-0x2021, 0x108042, 0x1600fffc, 0x0,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x97a2001a, 0x501025, 0xa7a2001a, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x0,
-0x3c040001, 0x24846bcc, 0x97a60018, 0x97a7001a,
-0x3c020001, 0x8c426d98, 0x3c030001, 0x8c636f1c,
-0x3c05000d, 0x34a50205, 0xafa20010, 0xc002b3b,
-0xafa30014, 0x8f830054, 0x24020004, 0x3c010001,
-0xac226dd4, 0x3c010001, 0x10000017, 0xac236f38,
-0x8f830054, 0x3c020001, 0x8c426f38, 0x2463ff9c,
-0x431023, 0x2c420064, 0x1440000f, 0x0,
-0x8f820220, 0x24030005, 0x3c010001, 0xac236dd4,
-0x3c03f700, 0x431025, 0x10000007, 0xaf820220,
-0x24020006, 0x3c010001, 0xac226dd4, 0x24020011,
-0x3c010001, 0xac226dd0, 0x8fbf0034, 0x8fb20030,
-0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0038,
-0x27bdffd8, 0xafb00018, 0x808021, 0xafb1001c,
-0x8821, 0x32024000, 0x10400013, 0xafbf0020,
-0x3c020010, 0x2021024, 0x2c420001, 0x21023,
-0x30434100, 0x3c020001, 0x2021024, 0x14400006,
-0x34714000, 0x3c020002, 0x2021024, 0x14400002,
-0x34716000, 0x34714040, 0x2021, 0x2821,
-0x10000036, 0x2203021, 0x32021000, 0x10400035,
-0x2021, 0x2821, 0xc004ddb, 0x24060040,
-0x24040018, 0x2821, 0xc004ddb, 0x24060c00,
-0x24040017, 0x2821, 0xc004ddb, 0x24060400,
-0x24040016, 0x2821, 0xc004ddb, 0x24060006,
-0x24040017, 0x2821, 0xc004ddb, 0x24062500,
-0x24040016, 0x2821, 0xc004ddb, 0x24060006,
-0x24040017, 0x2821, 0xc004ddb, 0x24064600,
-0x24040016, 0x2821, 0xc004ddb, 0x24060006,
-0x24040017, 0x2821, 0xc004ddb, 0x24066700,
-0x24040016, 0x2821, 0xc004ddb, 0x24060006,
-0x2404001f, 0x2821, 0xc004ddb, 0x24060010,
-0x24040009, 0x2821, 0xc004ddb, 0x24061500,
-0x24040009, 0x2821, 0x24061d00, 0xc004ddb,
-0x0, 0x3c040001, 0x24846bf0, 0x3c05000e,
-0x34a50100, 0x2003021, 0x2203821, 0xafa00010,
-0xc002b3b, 0xafa00014, 0x8fbf0020, 0x8fb1001c,
-0x8fb00018, 0x3e00008, 0x27bd0028, 0x8f850044,
-0x8f820044, 0x3c030001, 0x431025, 0x3c030008,
-0xaf820044, 0x8f840054, 0x8f820054, 0xa32824,
-0x10000002, 0x24840001, 0x8f820054, 0x821023,
-0x2c420002, 0x1440fffc, 0x0, 0x8f820044,
-0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
-0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
-0x0, 0x3e00008, 0xa01021, 0x8f830044,
-0x3c02fff0, 0x3442ffff, 0x42480, 0x621824,
-0x3c020002, 0x822025, 0x641825, 0xaf830044,
-0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024,
-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820044, 0x3c030001,
-0x431025, 0xaf820044, 0x8f830054, 0x8f820054,
-0x10000002, 0x24630001, 0x8f820054, 0x621023,
-0x2c420002, 0x1440fffc, 0x0, 0x3e00008,
-0x0, 0x8f820044, 0x2403ff7f, 0x431024,
-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820044, 0x34420080,
-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x3e00008, 0x0,
-0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024,
-0xaf820044, 0x8f820044, 0x3c030001, 0x431025,
-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
-0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
-0x809821, 0xafbe002c, 0xa0f021, 0xafb20020,
-0xc09021, 0x33c2ffff, 0xafbf0030, 0xafb50028,
-0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010,
-0x3271ffff, 0x27b20010, 0x8021, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x2301024, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x34108000,
-0x96420000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x12000075,
-0x0, 0x1000fff6, 0x0, 0x3275ffff,
-0x27b10010, 0xa7a00010, 0x8021, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
-0x2021, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x2b01024,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x2b01024, 0xc004db9,
-0x34108000, 0xc004db9, 0x0, 0xc004d58,
-0x0, 0x50400005, 0x108042, 0x96220000,
-0x501025, 0xa6220000, 0x108042, 0x1600fff7,
-0x0, 0xc004db9, 0x0, 0x33c5ffff,
-0x24020001, 0x54a20004, 0x24020002, 0x97a20010,
-0x10000006, 0x521025, 0x14a20006, 0x3271ffff,
-0x97a20010, 0x121827, 0x431024, 0xa7a20010,
-0x3271ffff, 0x27b20010, 0x8021, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x2301024, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x34108000,
-0x96420000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
-0x0, 0xc004db9, 0x0, 0x8fbf0030,
-0x8fbe002c, 0x8fb50028, 0x8fb30024, 0x8fb20020,
-0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038,
-0x0, 0x0, 0x0, 0x27bdffe8,
-0xafbf0010, 0x8ee304b8, 0x24020008, 0x146201e0,
-0x0, 0x3c020001, 0x8c426f1c, 0x14400005,
-0x0, 0xc003daf, 0x8f840224, 0x100001d8,
-0x0, 0x8f820220, 0x3c030008, 0x431024,
-0x10400026, 0x24020001, 0x8f840224, 0x8f820220,
-0x3c030400, 0x431024, 0x10400006, 0x0,
-0x3c010002, 0xac208fa0, 0x3c010002, 0x1000000b,
-0xac208fc0, 0x3c030002, 0x24638fa0, 0x8c620000,
-0x24420001, 0xac620000, 0x2c420002, 0x14400003,
-0x24020001, 0x3c010002, 0xac228fc0, 0x3c020002,
-0x8c428fc0, 0x10400006, 0x30820040, 0x10400004,
-0x24020001, 0x3c010002, 0x10000003, 0xac228fc4,
-0x3c010002, 0xac208fc4, 0x3c010002, 0xac248f9c,
-0x3c010002, 0x1000000b, 0xac208fd0, 0x3c010002,
-0xac228fd0, 0x3c010002, 0xac208fc0, 0x3c010002,
-0xac208fa0, 0x3c010002, 0xac208fc4, 0x3c010002,
-0xac208f9c, 0x3c030002, 0x8c638f90, 0x3c020002,
-0x8c428f94, 0x50620004, 0x2463ffff, 0x3c010002,
-0xac238f94, 0x2463ffff, 0x2c62000e, 0x10400194,
-0x31080, 0x3c010001, 0x220821, 0x8c226c00,
-0x400008, 0x0, 0x24020002, 0x3c010002,
-0xac208fc0, 0x3c010002, 0xac208fa0, 0x3c010002,
-0xac208f9c, 0x3c010002, 0xac208fc4, 0x3c010002,
-0xac208fb8, 0x3c010002, 0xac208fb0, 0xaf800224,
-0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fd0,
-0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003daf,
-0x282a024, 0xaf800204, 0x8f820200, 0x2403fffd,
-0x431024, 0xaf820200, 0x3c010002, 0xac208fe0,
-0x8f830054, 0x3c020002, 0x8c428fb8, 0x24040001,
-0x3c010002, 0xac248fcc, 0x24420001, 0x3c010002,
-0xac228fb8, 0x2c420004, 0x3c010002, 0xac238fb4,
-0x14400006, 0x24020003, 0x3c010001, 0xac246d9c,
-0x3c010002, 0x1000015e, 0xac208fb8, 0x3c010002,
-0x1000015b, 0xac228f90, 0x8f830054, 0x3c020002,
-0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710,
-0x14400003, 0x24020004, 0x3c010002, 0xac228f90,
-0x3c020002, 0x8c428fd0, 0x14400021, 0x3c02fdff,
-0x3442ffff, 0x1000014a, 0x282a024, 0x3c040001,
-0x8c846f20, 0x3c010002, 0xc005084, 0xac208fa8,
-0x3c020002, 0x8c428fdc, 0xaf820204, 0x3c020002,
-0x8c428fd0, 0x14400012, 0x3c03fdff, 0x8f820204,
-0x3463ffff, 0x30420030, 0x1440012f, 0x283a024,
-0x3c030002, 0x8c638fdc, 0x24020005, 0x3c010002,
-0xac228f90, 0x3c010002, 0x10000131, 0xac238fe0,
-0x3c020002, 0x8c428fd0, 0x10400010, 0x3c02fdff,
-0x3c020001, 0x8c426e3c, 0x24420001, 0x3c010001,
-0xac226e3c, 0x2c420002, 0x14400125, 0x24020001,
-0x3c010001, 0xac226e44, 0x3c010001, 0xac206e3c,
-0x3c010001, 0x1000011e, 0xac226d9c, 0x3c030002,
-0x8c638fc0, 0x3442ffff, 0x10600119, 0x282a024,
-0x3c020002, 0x8c428f9c, 0x10400115, 0x0,
-0x3c010002, 0xac228fc8, 0x24020003, 0x3c010002,
-0xac228fa0, 0x100000b8, 0x24020006, 0x3c010002,
-0xac208fa8, 0x8f820204, 0x34420040, 0xaf820204,
-0x3c020002, 0x8c428fe0, 0x24030007, 0x3c010002,
-0xac238f90, 0x34420040, 0x3c010002, 0xac228fe0,
-0x3c020002, 0x8c428fc0, 0x10400005, 0x0,
-0x3c020002, 0x8c428f9c, 0x104000f0, 0x24020002,
-0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21,
-0x104000ea, 0x24020002, 0x3c020002, 0x8c428fc4,
-0x104000ef, 0x2404ffbf, 0x3c020002, 0x8c428f9c,
-0x3c030002, 0x8c638fc8, 0x441024, 0x641824,
-0x10430004, 0x24020001, 0x3c010002, 0x100000e4,
-0xac228f90, 0x24020003, 0xaca20000, 0x24020008,
-0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fcc,
-0x1040000c, 0x24020001, 0x3c040002, 0xc005091,
-0x8c848f9c, 0x3c020002, 0x8c428fe8, 0x14400005,
-0x24020001, 0x3c020002, 0x8c428fe4, 0x10400006,
-0x24020001, 0x3c010001, 0xac226d9c, 0x3c010002,
-0x100000cb, 0xac208fb8, 0x3c020002, 0x8c428fb0,
-0x3c030002, 0x8c638f9c, 0x2c420001, 0x210c0,
-0x30630008, 0x3c010002, 0xac228fb0, 0x3c010002,
-0xac238fac, 0x8f830054, 0x24020009, 0x3c010002,
-0xac228f90, 0x3c010002, 0x100000b9, 0xac238fb4,
-0x8f830054, 0x3c020002, 0x8c428fb4, 0x2463d8f0,
-0x431023, 0x2c422710, 0x1440009f, 0x0,
-0x3c020002, 0x8c428fc0, 0x10400005, 0x0,
-0x3c020002, 0x8c428f9c, 0x104000a0, 0x24020002,
-0x3c030002, 0x24638fa0, 0x8c620000, 0x2c424e21,
-0x1040009a, 0x24020002, 0x3c020002, 0x8c428fcc,
-0x1040000e, 0x0, 0x3c020002, 0x8c428f9c,
-0x3c010002, 0xac208fcc, 0x30420080, 0x1040002f,
-0x2402000c, 0x8f820204, 0x30420080, 0x1440000c,
-0x24020003, 0x10000029, 0x2402000c, 0x3c020002,
-0x8c428f9c, 0x30420080, 0x14400005, 0x24020003,
-0x8f820204, 0x30420080, 0x1040001f, 0x24020003,
-0xac620000, 0x2402000a, 0x3c010002, 0xac228f90,
-0x3c040002, 0x24848fd8, 0x8c820000, 0x3c030002,
-0x8c638fb0, 0x431025, 0xaf820204, 0x8c830000,
-0x3c040002, 0x8c848fb0, 0x2402000b, 0x3c010002,
-0xac228f90, 0x641825, 0x3c010002, 0xac238fe0,
-0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21,
-0x10400066, 0x24020002, 0x3c020002, 0x8c428fd0,
-0x10400005, 0x0, 0x2402000c, 0x3c010002,
-0x10000067, 0xac228f90, 0x3c020002, 0x8c428fc0,
-0x10400063, 0x0, 0x3c040002, 0x8c848f9c,
-0x10800055, 0x30820008, 0x3c030002, 0x8c638fac,
-0x1062005b, 0x24020003, 0x3c010002, 0xac248fc8,
-0xaca20000, 0x24020006, 0x3c010002, 0x10000054,
-0xac228f90, 0x8f820200, 0x34420002, 0xaf820200,
-0x8f830054, 0x2402000d, 0x3c010002, 0xac228f90,
-0x3c010002, 0xac238fb4, 0x8f830054, 0x3c020002,
-0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710,
-0x14400031, 0x0, 0x3c020002, 0x8c428fd0,
-0x10400020, 0x2402000e, 0x3c030002, 0x8c638fe4,
-0x3c010002, 0x14600015, 0xac228f90, 0xc003e6d,
-0x0, 0x3c050001, 0x8ca56d98, 0xc00529b,
-0x2021, 0x3c030001, 0x8c636d98, 0x24020004,
-0x14620005, 0x2403fffb, 0x3c020001, 0x8c426d94,
-0x10000003, 0x2403fff7, 0x3c020001, 0x8c426d94,
-0x431024, 0x3c010001, 0xac226d94, 0x8f830224,
-0x3c020200, 0x3c010002, 0xac238fec, 0x10000020,
-0x282a025, 0x3c020002, 0x8c428fc0, 0x10400005,
-0x0, 0x3c020002, 0x8c428f9c, 0x1040000f,
-0x24020002, 0x3c020002, 0x8c428fa0, 0x2c424e21,
-0x1040000a, 0x24020002, 0x3c020002, 0x8c428fc0,
-0x1040000f, 0x0, 0x3c020002, 0x8c428f9c,
-0x1440000b, 0x0, 0x24020002, 0x3c010002,
-0x10000007, 0xac228f90, 0x3c020002, 0x8c428fc0,
-0x10400003, 0x0, 0xc003daf, 0x0,
-0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
-0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030002,
-0x24638fe8, 0x8c620000, 0x10400005, 0x34422000,
-0x3c010002, 0xac228fdc, 0x10000003, 0xac600000,
-0x3c010002, 0xac248fdc, 0x3e00008, 0x0,
-0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010002,
-0xac228fe4, 0x14400067, 0x3c02ffff, 0x34421f0e,
-0x821024, 0x14400061, 0x24020030, 0x30822000,
-0x1040005d, 0x30838000, 0x31a02, 0x30820001,
-0x21200, 0x3c040001, 0x8c846f20, 0x621825,
-0x331c2, 0x3c030001, 0x24636e48, 0x30828000,
-0x21202, 0x30840001, 0x42200, 0x441025,
-0x239c2, 0x61080, 0x431021, 0x471021,
-0x90430000, 0x24020001, 0x10620025, 0x0,
-0x10600007, 0x24020002, 0x10620013, 0x24020003,
-0x1062002c, 0x3c05000f, 0x10000037, 0x0,
-0x8f820200, 0x2403feff, 0x431024, 0xaf820200,
-0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024,
-0xaf820220, 0x3c010002, 0xac209004, 0x3c010002,
-0x10000034, 0xac20900c, 0x8f820200, 0x34420100,
-0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff,
-0x431024, 0xaf820220, 0x24020100, 0x3c010002,
-0xac229004, 0x3c010002, 0x10000026, 0xac20900c,
-0x8f820200, 0x2403feff, 0x431024, 0xaf820200,
-0x8f820220, 0x3c030001, 0x431025, 0xaf820220,
-0x3c010002, 0xac209004, 0x3c010002, 0x10000019,
-0xac23900c, 0x8f820200, 0x34420100, 0xaf820200,
-0x8f820220, 0x3c030001, 0x431025, 0xaf820220,
-0x24020100, 0x3c010002, 0xac229004, 0x3c010002,
-0x1000000c, 0xac23900c, 0x34a5ffff, 0x3c040001,
-0x24846c38, 0xafa30010, 0xc002b3b, 0xafa00014,
-0x10000004, 0x0, 0x24020030, 0x3c010002,
-0xac228fe8, 0x8fbf0018, 0x3e00008, 0x27bd0020,
-0x0, 0x0, 0x0, 0x27bdffc8,
-0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
-0xafb00020, 0xc08021, 0x3c040001, 0x24846c50,
-0x3c050009, 0x3c020001, 0x8c426d98, 0x34a59001,
-0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
-0xa7a0001a, 0xafb00014, 0xc002b3b, 0xafa20010,
-0x24020002, 0x12620083, 0x2e620003, 0x10400005,
-0x24020001, 0x1262000a, 0x0, 0x10000173,
-0x0, 0x24020004, 0x126200f8, 0x24020008,
-0x126200f7, 0x3c02ffec, 0x1000016c, 0x0,
-0x3c020001, 0x8c426d94, 0x30420002, 0x14400004,
-0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
-0x3c010002, 0x310821, 0xac308ffc, 0x3c024000,
-0x2021024, 0x1040004e, 0x1023c2, 0x30840030,
-0x101382, 0x3042001c, 0x3c030001, 0x24636dd8,
-0x431021, 0x823821, 0x3c020020, 0x2021024,
-0x10400006, 0x24020100, 0x3c010002, 0x310821,
-0xac229000, 0x10000005, 0x3c020080, 0x3c010002,
-0x310821, 0xac209000, 0x3c020080, 0x2021024,
-0x10400006, 0x121940, 0x3c020001, 0x3c010002,
-0x230821, 0x10000005, 0xac229008, 0x121140,
-0x3c010002, 0x220821, 0xac209008, 0x94e40000,
-0x3c030001, 0x8c636f40, 0x24020005, 0x10620010,
-0xa7a40018, 0x32024000, 0x10400002, 0x34824000,
-0xa7a20018, 0x24040001, 0x94e20002, 0x24050004,
-0x24e60002, 0x34420001, 0xc0045be, 0xa4e20002,
-0x24040001, 0x2821, 0xc0045be, 0x27a60018,
-0x3c020001, 0x8c426d98, 0x24110001, 0x3c010001,
-0xac316da4, 0x14530004, 0x32028000, 0xc003daf,
-0x0, 0x32028000, 0x1040011c, 0x0,
-0xc003daf, 0x0, 0x3c030001, 0x8c636f40,
-0x24020005, 0x10620115, 0x24020002, 0x3c010001,
-0xac316d9c, 0x3c010001, 0x10000110, 0xac226d98,
-0x24040001, 0x24050004, 0x27b0001a, 0xc0045be,
-0x2003021, 0x24040001, 0x2821, 0xc0045be,
-0x2003021, 0x3c020002, 0x511021, 0x8c428ff4,
-0x3c040001, 0x8c846d98, 0x3c03bfff, 0x3463ffff,
-0x3c010001, 0xac336da4, 0x431024, 0x3c010002,
-0x310821, 0x109300f7, 0xac228ff4, 0x100000f7,
-0x0, 0x3c022000, 0x2021024, 0x10400005,
-0x24020001, 0x3c010001, 0xac226f1c, 0x10000004,
-0x128940, 0x3c010001, 0xac206f1c, 0x128940,
-0x3c010002, 0x310821, 0xac308ff8, 0x3c024000,
-0x2021024, 0x14400014, 0x0, 0x3c020001,
-0x8c426f1c, 0x10400006, 0x24040004, 0x24050001,
-0xc004ddb, 0x24062000, 0x24020001, 0xaee204b8,
-0x3c020002, 0x511021, 0x8c428ff0, 0x3c03bfff,
-0x3463ffff, 0x431024, 0x3c010002, 0x310821,
-0x100000d0, 0xac228ff0, 0x3c020001, 0x8c426f1c,
-0x10400028, 0x3c0300a0, 0x2031024, 0x5443000d,
-0x3c020020, 0x3c020001, 0x8c426f20, 0x24030100,
-0x3c010002, 0x310821, 0xac239004, 0x3c030001,
-0x3c010002, 0x310821, 0xac23900c, 0x10000015,
-0x34420400, 0x2021024, 0x10400008, 0x24030100,
-0x3c020001, 0x8c426f20, 0x3c010002, 0x310821,
-0xac239004, 0x1000000b, 0x34420800, 0x3c020080,
-0x2021024, 0x1040002e, 0x3c030001, 0x3c020001,
-0x8c426f20, 0x3c010002, 0x310821, 0xac23900c,
-0x34420c00, 0x3c010001, 0xac226f20, 0x10000025,
-0x24040001, 0x3c020020, 0x2021024, 0x10400006,
-0x24020100, 0x3c010002, 0x310821, 0xac229004,
-0x10000005, 0x3c020080, 0x3c010002, 0x310821,
-0xac209004, 0x3c020080, 0x2021024, 0x10400007,
-0x121940, 0x3c020001, 0x3c010002, 0x230821,
-0xac22900c, 0x10000006, 0x24040001, 0x121140,
-0x3c010002, 0x220821, 0xac20900c, 0x24040001,
-0x2821, 0x27b0001e, 0xc00457c, 0x2003021,
-0x24040001, 0x2821, 0xc00457c, 0x2003021,
-0x24040001, 0x24050001, 0x27b0001c, 0xc00457c,
-0x2003021, 0x24040001, 0x24050001, 0xc00457c,
-0x2003021, 0x10000077, 0x0, 0x3c02ffec,
-0x3442ffff, 0x2028024, 0x3c020008, 0x2028025,
-0x121140, 0x3c010002, 0x220821, 0xac308ff8,
-0x3c022000, 0x2021024, 0x10400009, 0x0,
-0x3c020001, 0x8c426e44, 0x14400005, 0x24020001,
-0x3c010001, 0xac226f1c, 0x10000004, 0x3c024000,
-0x3c010001, 0xac206f1c, 0x3c024000, 0x2021024,
-0x1440001d, 0x24020e01, 0x3c030001, 0x8c636f1c,
-0xaf820238, 0x3c010001, 0xac206db0, 0x10600005,
-0x24022020, 0x3c010001, 0xac226f20, 0x24020001,
-0xaee204b8, 0x3c04bfff, 0x121940, 0x3c020002,
-0x431021, 0x8c428ff0, 0x3c050001, 0x8ca56d98,
-0x3484ffff, 0x441024, 0x3c010002, 0x230821,
-0xac228ff0, 0x24020001, 0x10a20044, 0x0,
-0x10000040, 0x0, 0x3c020001, 0x8c426f1c,
-0x1040001c, 0x24022000, 0x3c010001, 0xac226f20,
-0x3c0300a0, 0x2031024, 0x14430005, 0x121140,
-0x3402a000, 0x3c010001, 0x1000002d, 0xac226f20,
-0x3c030002, 0x621821, 0x8c638ff8, 0x3c020020,
-0x621024, 0x10400004, 0x24022001, 0x3c010001,
-0x10000023, 0xac226f20, 0x3c020080, 0x621024,
-0x1040001f, 0x3402a001, 0x3c010001, 0x1000001c,
-0xac226f20, 0x3c020020, 0x2021024, 0x10400007,
-0x121940, 0x24020100, 0x3c010002, 0x230821,
-0xac229004, 0x10000006, 0x3c020080, 0x121140,
-0x3c010002, 0x220821, 0xac209004, 0x3c020080,
-0x2021024, 0x10400006, 0x121940, 0x3c020001,
-0x3c010002, 0x230821, 0x10000005, 0xac22900c,
-0x121140, 0x3c010002, 0x220821, 0xac20900c,
-0x3c030001, 0x8c636d98, 0x24020001, 0x10620003,
-0x0, 0xc003daf, 0x0, 0x8fbf0030,
-0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
-0x3e00008, 0x27bd0038, 0x27bdffb0, 0xafb3003c,
-0x9821, 0xafb50040, 0xa821, 0xafb10034,
-0x8821, 0x24020002, 0xafbf0048, 0xafbe0044,
-0xafb20038, 0xafb00030, 0xafa4002c, 0xa7a0001a,
-0xa7a00018, 0xa7a00020, 0xa7a0001e, 0xa7a00022,
-0x10a20130, 0xa7a0001c, 0x2ca20003, 0x10400005,
-0x24020001, 0x10a2000a, 0x3c024000, 0x1000025d,
-0x2201021, 0x24020004, 0x10a2020a, 0x24020008,
-0x10a20208, 0x2201021, 0x10000256, 0x0,
-0x8fa8002c, 0x88140, 0x3c030002, 0x701821,
-0x8c638ffc, 0x621024, 0x14400009, 0x24040001,
-0x3c027fff, 0x3442ffff, 0x628824, 0x3c010002,
-0x300821, 0xac318ff4, 0x10000246, 0x2201021,
-0x24050001, 0xc00457c, 0x27a60018, 0x24040001,
-0x24050001, 0xc00457c, 0x27a60018, 0x97a20018,
-0x30420004, 0x104000d9, 0x3c114000, 0x3c020001,
-0x8c426f40, 0x2443ffff, 0x2c620006, 0x104000d9,
-0x31080, 0x3c010001, 0x220821, 0x8c226c68,
-0x400008, 0x0, 0x24040001, 0x24050011,
-0x27b0001a, 0xc00457c, 0x2003021, 0x24040001,
-0x24050011, 0xc00457c, 0x2003021, 0x97a3001a,
-0x30624000, 0x10400002, 0x3c150010, 0x3c150008,
-0x30628000, 0x104000aa, 0x3c130001, 0x100000a8,
-0x3c130002, 0x24040001, 0x24050014, 0x27b0001a,
-0xc00457c, 0x2003021, 0x24040001, 0x24050014,
-0xc00457c, 0x2003021, 0x97a3001a, 0x30621000,
-0x10400002, 0x3c150010, 0x3c150008, 0x30620800,
-0x10400097, 0x3c130001, 0x10000095, 0x3c130002,
-0x24040001, 0x24050019, 0x27b0001c, 0xc00457c,
-0x2003021, 0x24040001, 0x24050019, 0xc00457c,
-0x2003021, 0x97a2001c, 0x30430700, 0x24020400,
-0x10620027, 0x28620401, 0x1040000e, 0x24020200,
-0x1062001f, 0x28620201, 0x10400005, 0x24020100,
-0x5062001e, 0x3c130001, 0x1000001e, 0x24040001,
-0x24020300, 0x50620019, 0x3c130002, 0x10000019,
-0x24040001, 0x24020600, 0x1062000d, 0x28620601,
-0x10400005, 0x24020500, 0x5062000b, 0x3c130002,
-0x10000010, 0x24040001, 0x24020700, 0x1462000d,
-0x24040001, 0x3c130004, 0x1000000a, 0x3c150008,
-0x10000006, 0x3c130004, 0x10000005, 0x3c150008,
-0x3c130001, 0x10000002, 0x3c150008, 0x3c150010,
-0x24040001, 0x24050018, 0x27b0001e, 0xc00457c,
-0x2003021, 0x24040001, 0x24050018, 0xc00457c,
-0x2003021, 0x8fa8002c, 0x97a7001e, 0x81140,
-0x3c060002, 0xc23021, 0x8cc68ff4, 0x97a20022,
-0x3c100001, 0x26106c5c, 0x2002021, 0xafa20010,
-0x97a2001c, 0x3c05000c, 0x34a50303, 0xc002b3b,
-0xafa20014, 0x3c020004, 0x16620010, 0x3c020001,
-0x8f840054, 0x24030001, 0x24020002, 0x3c010001,
-0xac236d9c, 0x3c010001, 0xac226d98, 0x3c010001,
-0xac236da4, 0x3c010001, 0xac236e24, 0x3c010001,
-0xac246f30, 0x1000004f, 0x2b38825, 0x16620039,
-0x3c028000, 0x3c020001, 0x8c426e20, 0x1440001e,
-0x24040018, 0x2021, 0x2821, 0xc004ddb,
-0x34068000, 0x8f830054, 0x8f820054, 0x2b38825,
-0x10000002, 0x24630032, 0x8f820054, 0x621023,
-0x2c420033, 0x1440fffc, 0x0, 0x8f830054,
-0x24020001, 0x3c010001, 0xac226e20, 0x3c010001,
-0xac226d9c, 0x3c010001, 0xac226d98, 0x3c010001,
-0xac226da4, 0x3c010001, 0xac226e24, 0x3c010001,
-0x1000002c, 0xac236f30, 0x2821, 0xc004ddb,
-0x24060404, 0x2021, 0x2405001e, 0x27a60018,
-0x24020002, 0xc0045be, 0xa7a20018, 0x2021,
-0x2821, 0x27a60018, 0xc0045be, 0xa7a00018,
-0x24040018, 0x24050002, 0xc004ddb, 0x24060004,
-0x3c028000, 0x2221025, 0x2b31825, 0x10000015,
-0x438825, 0x2221025, 0x2751825, 0x438825,
-0x2002021, 0x97a6001c, 0x3c070001, 0x8ce76d98,
-0x3c05000c, 0x34a50326, 0xafb30010, 0xc002b3b,
-0xafb10014, 0x10000007, 0x0, 0x3c110002,
-0x2308821, 0x8e318ffc, 0x3c027fff, 0x3442ffff,
-0x2228824, 0x3c020001, 0x8c426da8, 0x1040001e,
-0x0, 0x3c020001, 0x8c426f1c, 0x10400002,
-0x3c022000, 0x2228825, 0x8fa8002c, 0x81140,
-0x3c010002, 0x220821, 0x8c229000, 0x10400003,
-0x3c020020, 0x10000005, 0x2228825, 0x3c02ffdf,
-0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140,
-0x3c010002, 0x220821, 0x8c229008, 0x10400003,
-0x3c020080, 0x10000004, 0x2228825, 0x3c02ff7f,
-0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140,
-0x3c010002, 0x220821, 0xac318ff4, 0x10000135,
-0x2201021, 0x8fa8002c, 0x8f140, 0x3c030002,
-0x7e1821, 0x8c638ff8, 0x3c024000, 0x621024,
-0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff,
-0x628824, 0x3c010002, 0x3e0821, 0xac318ff0,
-0x10000124, 0x2201021, 0x2821, 0xc00457c,
-0x27a60018, 0x24040001, 0x2821, 0xc00457c,
-0x27a60018, 0x24040001, 0x24050001, 0x27b20020,
-0xc00457c, 0x2403021, 0x24040001, 0x24050001,
-0xc00457c, 0x2403021, 0x24040001, 0x24050004,
-0x27b1001e, 0xc00457c, 0x2203021, 0x24040001,
-0x24050004, 0xc00457c, 0x2203021, 0x24040001,
-0x24050005, 0x27b00022, 0xc00457c, 0x2003021,
-0x24040001, 0x24050005, 0xc00457c, 0x2003021,
-0x24040001, 0x24050010, 0xc00457c, 0x27a60018,
-0x24040001, 0x24050010, 0xc00457c, 0x27a60018,
-0x24040001, 0x2405000a, 0xc00457c, 0x2403021,
-0x24040001, 0x2405000a, 0xc00457c, 0x2403021,
-0x24040001, 0x24050018, 0xc00457c, 0x2203021,
-0x24040001, 0x24050018, 0xc00457c, 0x2203021,
-0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
-0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
-0x97a20018, 0x30420004, 0x10400066, 0x3c114000,
-0x3c030001, 0x8c636f34, 0x24020005, 0x14620067,
-0x24040001, 0x24050019, 0x27b0001c, 0xc00457c,
-0x2003021, 0x24040001, 0x24050019, 0xc00457c,
-0x2003021, 0x97a2001c, 0x30430700, 0x24020400,
-0x10620027, 0x28620401, 0x1040000e, 0x24020200,
-0x1062001f, 0x28620201, 0x10400005, 0x24020100,
-0x5062001e, 0x3c130001, 0x1000001e, 0x3c020004,
-0x24020300, 0x50620019, 0x3c130002, 0x10000019,
-0x3c020004, 0x24020600, 0x1062000d, 0x28620601,
-0x10400005, 0x24020500, 0x5062000b, 0x3c130002,
-0x10000010, 0x3c020004, 0x24020700, 0x1462000d,
-0x3c020004, 0x3c130004, 0x1000000a, 0x3c150008,
-0x10000006, 0x3c130004, 0x10000005, 0x3c150008,
-0x3c130001, 0x10000002, 0x3c150008, 0x3c150010,
-0x3c020004, 0x12620017, 0x3c028000, 0x8f820054,
-0x24100001, 0x3c010001, 0xac306d9c, 0x3c010001,
-0xac306d98, 0x3c010001, 0xac306da4, 0x3c010001,
-0xac306e24, 0x3c010001, 0xac226f30, 0x3c020001,
-0x16620022, 0x2758825, 0x2021, 0x2821,
-0xc004ddb, 0x34068000, 0x3c010001, 0x1000001b,
-0xac306e20, 0x2221025, 0x2b31825, 0x438825,
-0x97a6001c, 0x3c020001, 0x8c426f1c, 0x3c070001,
-0x8ce76d98, 0x3c040001, 0x24846c5c, 0xafa20010,
-0x97a2001e, 0x3c05000c, 0x34a50323, 0x3c010001,
-0xac206e20, 0xc002b3b, 0xafa20014, 0x10000007,
-0x0, 0x3c110002, 0x23e8821, 0x8e318ff0,
-0x3c027fff, 0x3442ffff, 0x2228824, 0x3c020001,
-0x8c426da8, 0x10400069, 0x0, 0x3c020001,
-0x8c426f1c, 0x10400002, 0x3c022000, 0x2228825,
-0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
-0x8c229004, 0x10400003, 0x3c020020, 0x10000005,
-0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
-0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
-0x8c22900c, 0x10400003, 0x3c020080, 0x1000004f,
-0x2228825, 0x3c02ff7f, 0x3442ffff, 0x1000004b,
-0x2228824, 0x8fa8002c, 0x82940, 0x3c030002,
-0x651821, 0x8c638ff8, 0x3c024000, 0x621024,
-0x14400008, 0x3c027fff, 0x3442ffff, 0x628824,
-0x3c010002, 0x250821, 0xac318ff0, 0x10000041,
-0x2201021, 0x3c020001, 0x8c426da8, 0x10400034,
-0x3c11c00c, 0x3c020001, 0x8c426e44, 0x3c04c00c,
-0x34842000, 0x3c030001, 0x8c636f1c, 0x2102b,
-0x21023, 0x441024, 0x10600003, 0x518825,
-0x3c022000, 0x2228825, 0x3c020002, 0x451021,
-0x8c429004, 0x10400003, 0x3c020020, 0x10000004,
-0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
-0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
-0x8c22900c, 0x10400003, 0x3c020080, 0x10000004,
-0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824,
-0x3c020001, 0x8c426e30, 0x10400002, 0x3c020800,
-0x2228825, 0x3c020001, 0x8c426e34, 0x10400002,
-0x3c020400, 0x2228825, 0x3c020001, 0x8c426e38,
-0x10400006, 0x3c020100, 0x10000004, 0x2228825,
-0x3c027fff, 0x3442ffff, 0x628824, 0x8fa8002c,
-0x81140, 0x3c010002, 0x220821, 0xac318ff0,
-0x2201021, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
-0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
-0x3e00008, 0x27bd0050, 0x27bdffd0, 0xafb20028,
-0x809021, 0xafbf002c, 0xafb10024, 0xafb00020,
-0x8f840200, 0x3c100001, 0x8e106d98, 0x8f860220,
-0x24020002, 0x1202005c, 0x2e020003, 0x10400005,
-0x24020001, 0x1202000a, 0x121940, 0x1000010c,
-0x0, 0x24020004, 0x120200bf, 0x24020008,
-0x120200be, 0x128940, 0x10000105, 0x0,
-0x3c050002, 0xa32821, 0x8ca58ffc, 0x3c100002,
-0x2038021, 0x8e108ff4, 0x3c024000, 0xa21024,
-0x10400038, 0x3c020008, 0x2021024, 0x10400020,
-0x34840002, 0x3c020002, 0x431021, 0x8c429000,
-0x10400005, 0x34840020, 0x34840100, 0x3c020020,
-0x10000006, 0x2028025, 0x2402feff, 0x822024,
-0x3c02ffdf, 0x3442ffff, 0x2028024, 0x121140,
-0x3c010002, 0x220821, 0x8c229008, 0x10400005,
-0x3c020001, 0xc23025, 0x3c020080, 0x10000016,
-0x2028025, 0x3c02fffe, 0x3442ffff, 0xc23024,
-0x3c02ff7f, 0x3442ffff, 0x1000000f, 0x2028024,
-0x2402fedf, 0x822024, 0x3c02fffe, 0x3442ffff,
-0xc23024, 0x3c02ff5f, 0x3442ffff, 0x2028024,
-0x3c010002, 0x230821, 0xac209000, 0x3c010002,
-0x230821, 0xac209008, 0xaf840200, 0xaf860220,
-0x8f820220, 0x34420002, 0xaf820220, 0x1000000a,
-0x121140, 0x3c02bfff, 0x3442ffff, 0x8f830200,
-0x2028024, 0x2402fffd, 0x621824, 0xc003daf,
-0xaf830200, 0x121140, 0x3c010002, 0x220821,
-0x100000b7, 0xac308ff4, 0x3c020001, 0x8c426f1c,
-0x10400069, 0x24050004, 0x24040001, 0xc00457c,
-0x27a60018, 0x24040001, 0x24050005, 0xc00457c,
-0x27a6001a, 0x97a30018, 0x97a2001a, 0x3c040001,
-0x24846e48, 0x30630c00, 0x31a82, 0x30420c00,
-0x21282, 0xa7a2001a, 0x21080, 0x441021,
-0x431021, 0xa7a30018, 0x90480000, 0x24020001,
-0x3103ffff, 0x10620029, 0x28620002, 0x10400005,
-0x0, 0x10600009, 0x0, 0x1000003d,
-0x0, 0x10700013, 0x24020003, 0x1062002c,
-0x0, 0x10000037, 0x0, 0x8f820200,
-0x2403feff, 0x431024, 0xaf820200, 0x8f820220,
-0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
-0x3c010002, 0xac209004, 0x3c010002, 0x10000032,
-0xac20900c, 0x8f820200, 0x34420100, 0xaf820200,
-0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024,
-0xaf820220, 0x24020100, 0x3c010002, 0xac229004,
-0x3c010002, 0x10000024, 0xac20900c, 0x8f820200,
-0x2403feff, 0x431024, 0xaf820200, 0x8f820220,
-0x3c030001, 0x431025, 0xaf820220, 0x3c010002,
-0xac209004, 0x3c010002, 0x10000017, 0xac23900c,
-0x8f820200, 0x34420100, 0xaf820200, 0x8f820220,
-0x3c030001, 0x431025, 0xaf820220, 0x24020100,
-0x3c010002, 0xac229004, 0x3c010002, 0x1000000a,
-0xac23900c, 0x3c040001, 0x24846c80, 0x97a6001a,
-0x97a70018, 0x3c050001, 0x34a5ffff, 0xafa80010,
-0xc002b3b, 0xafa00014, 0x8f820200, 0x34420002,
-0x1000004b, 0xaf820200, 0x128940, 0x3c050002,
-0xb12821, 0x8ca58ff8, 0x3c100002, 0x2118021,
-0x8e108ff0, 0x3c024000, 0xa21024, 0x14400010,
-0x0, 0x3c020001, 0x8c426f1c, 0x14400005,
-0x3c02bfff, 0x8f820200, 0x34420002, 0xaf820200,
-0x3c02bfff, 0x3442ffff, 0xc003daf, 0x2028024,
-0x3c010002, 0x310821, 0x10000031, 0xac308ff0,
-0x3c020001, 0x8c426f1c, 0x10400005, 0x3c020020,
-0x3c020001, 0x8c426e44, 0x10400025, 0x3c020020,
-0xa21024, 0x10400007, 0x34840020, 0x24020100,
-0x3c010002, 0x310821, 0xac229004, 0x10000006,
-0x34840100, 0x3c010002, 0x310821, 0xac209004,
-0x2402feff, 0x822024, 0x3c020080, 0xa21024,
-0x10400007, 0x121940, 0x3c020001, 0x3c010002,
-0x230821, 0xac22900c, 0x10000008, 0xc23025,
-0x121140, 0x3c010002, 0x220821, 0xac20900c,
-0x3c02fffe, 0x3442ffff, 0xc23024, 0xaf840200,
-0xaf860220, 0x8f820220, 0x34420002, 0xaf820220,
-0x121140, 0x3c010002, 0x220821, 0xac308ff0,
-0x8fbf002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
-0x3e00008, 0x27bd0030, 0x0, 0x1821,
-0x308400ff, 0x2405ffdf, 0x2406ffbf, 0x641007,
-0x30420001, 0x10400004, 0x0, 0x8f820044,
-0x10000003, 0x34420040, 0x8f820044, 0x461024,
-0xaf820044, 0x8f820044, 0x34420020, 0xaf820044,
-0x8f820044, 0x451024, 0xaf820044, 0x24630001,
-0x28620008, 0x5440ffee, 0x641007, 0x3e00008,
-0x0, 0x2c820008, 0x1040001b, 0x0,
-0x2405ffdf, 0x2406ffbf, 0x41880, 0x3c020001,
-0x24426e60, 0x621821, 0x24640004, 0x90620000,
-0x10400004, 0x0, 0x8f820044, 0x10000003,
-0x34420040, 0x8f820044, 0x461024, 0xaf820044,
-0x8f820044, 0x34420020, 0xaf820044, 0x8f820044,
-0x451024, 0xaf820044, 0x24630001, 0x64102b,
-0x1440ffee, 0x0, 0x3e00008, 0x0,
-0x0, 0x0, 0x0, 0x8f8400c4,
-0x8f8600e0, 0x8f8700e4, 0x2402fff8, 0xc22824,
-0x10e5001a, 0x27623ff8, 0x14e20002, 0x24e80008,
-0x27683000, 0x55050004, 0x8d0a0000, 0x30c20004,
-0x14400012, 0x805021, 0x8ce90000, 0x8f42013c,
-0x1494823, 0x49182b, 0x94eb0006, 0x10600002,
-0x25630050, 0x494821, 0x123182b, 0x50400003,
-0x8f4201fc, 0x3e00008, 0xe01021, 0xaf8800e8,
-0x24420001, 0xaf4201fc, 0xaf8800e4, 0x3e00008,
-0x1021, 0x3e00008, 0x0, 0x8f8300e4,
-0x27623ff8, 0x10620004, 0x24620008, 0xaf8200e8,
-0x3e00008, 0xaf8200e4, 0x27623000, 0xaf8200e8,
-0x3e00008, 0xaf8200e4, 0x3e00008, 0x0,
-0x0, 0x0, 0x0, 0x8f880120,
-0x27624fe0, 0x8f830128, 0x15020002, 0x25090020,
-0x27694800, 0x11230012, 0x8fa20010, 0xad040000,
-0xad050004, 0xad060008, 0xa507000e, 0x8fa30014,
-0xad020018, 0x8fa20018, 0xad03001c, 0x25030016,
-0xad020010, 0xad030014, 0xaf890120, 0x8f4300fc,
-0x24020001, 0x2463ffff, 0x3e00008, 0xaf4300fc,
-0x8f430324, 0x1021, 0x24630001, 0x3e00008,
-0xaf430324, 0x3e00008, 0x0, 0x8f880100,
-0x276247e0, 0x8f830108, 0x15020002, 0x25090020,
-0x27694000, 0x1123000f, 0x8fa20010, 0xad040000,
-0xad050004, 0xad060008, 0xa507000e, 0x8fa30014,
-0xad020018, 0x8fa20018, 0xad03001c, 0x25030016,
-0xad020010, 0xad030014, 0xaf890100, 0x3e00008,
-0x24020001, 0x8f430328, 0x1021, 0x24630001,
-0x3e00008, 0xaf430328, 0x3e00008, 0x0,
-0x0, 0x0, 0x0, 0x0 };
-static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = {
-0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f6677, 0x6d61696e, 0x2e632c76, 0x20312e31,
-0x2e322e34, 0x35203139, 0x39392f30, 0x312f3234,
-0x2030303a, 0x31303a35, 0x35207368, 0x75616e67,
-0x20457870, 0x20240000, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x6261644d, 0x656d537a,
-0x0, 0x68775665, 0x72000000, 0x62616448,
-0x77566572, 0x0, 0x2a2a4441, 0x574e5f41,
-0x0, 0x74785278, 0x4266537a, 0x0,
-0x62664174, 0x6e4d726b, 0x0, 0x7265645a,
-0x6f6e6531, 0x0, 0x70636943, 0x6f6e6600,
-0x67656e43, 0x6f6e6600, 0x2a646d61, 0x5244666c,
-0x0, 0x2a50414e, 0x49432a00, 0x2e2e2f2e,
-0x2e2f2e2e, 0x2f2e2e2f, 0x2e2e2f73, 0x72632f6e,
-0x69632f66, 0x77322f63, 0x6f6d6d6f, 0x6e2f6677,
-0x6d61696e, 0x2e630000, 0x72636246, 0x6c616773,
-0x0, 0x62616452, 0x78526362, 0x0,
-0x676c6f62, 0x466c6773, 0x0, 0x2b5f6469,
-0x73705f6c, 0x6f6f7000, 0x2b65765f, 0x68616e64,
-0x6c657200, 0x63616e74, 0x31446d61, 0x0,
-0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x635f636b,
-0x73756d00, 0x2b685f73, 0x656e645f, 0x64617461,
-0x5f726561, 0x64795f63, 0x6b73756d, 0x0,
-0x2b685f64, 0x6d615f72, 0x645f6173, 0x73697374,
-0x5f636b73, 0x756d0000, 0x74436b73, 0x6d4f6e00,
-0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x63000000,
-0x2b685f73, 0x656e645f, 0x64617461, 0x5f726561,
-0x64790000, 0x2b685f64, 0x6d615f72, 0x645f6173,
-0x73697374, 0x0, 0x74436b73, 0x6d4f6666,
-0x0, 0x2b685f73, 0x656e645f, 0x62645f72,
-0x65616479, 0x0, 0x68737453, 0x52696e67,
-0x0, 0x62616453, 0x52696e67, 0x0,
-0x6e696353, 0x52696e67, 0x0, 0x77446d61,
-0x416c6c41, 0x0, 0x2b715f64, 0x6d615f74,
-0x6f5f686f, 0x73745f63, 0x6b73756d, 0x0,
-0x2b685f6d, 0x61635f72, 0x785f636f, 0x6d705f63,
-0x6b73756d, 0x0, 0x2b685f64, 0x6d615f77,
-0x725f6173, 0x73697374, 0x5f636b73, 0x756d0000,
-0x72436b73, 0x6d4f6e00, 0x2b715f64, 0x6d615f74,
-0x6f5f686f, 0x73740000, 0x2b685f6d, 0x61635f72,
-0x785f636f, 0x6d700000, 0x2b685f64, 0x6d615f77,
-0x725f6173, 0x73697374, 0x0, 0x72436b73,
-0x6d4f6666, 0x0, 0x2b685f72, 0x6563765f,
-0x62645f72, 0x65616479, 0x0, 0x2b685f72,
-0x6563765f, 0x6a756d62, 0x6f5f6264, 0x5f726561,
-0x64790000, 0x2b685f72, 0x6563765f, 0x6d696e69,
-0x5f62645f, 0x72656164, 0x79000000, 0x2b6d685f,
-0x636f6d6d, 0x616e6400, 0x2b685f74, 0x696d6572,
-0x0, 0x2b685f64, 0x6f5f7570, 0x64617465,
-0x5f74785f, 0x636f6e73, 0x0, 0x2b685f64,
-0x6f5f7570, 0x64617465, 0x5f72785f, 0x70726f64,
-0x0, 0x2b636b73, 0x756d3136, 0x0,
-0x2b706565, 0x6b5f6d61, 0x635f7278, 0x5f776100,
-0x2b706565, 0x6b5f6d61, 0x635f7278, 0x0,
-0x2b646571, 0x5f6d6163, 0x5f727800, 0x2b685f6d,
-0x61635f72, 0x785f6174, 0x746e0000, 0x62616452,
-0x6574537a, 0x0, 0x72784264, 0x4266537a,
-0x0, 0x2b6e756c, 0x6c5f6861, 0x6e646c65,
-0x72000000, 0x66774f70, 0x4661696c, 0x0,
-0x2b685f75, 0x70646174, 0x655f6c65, 0x64340000,
-0x2b685f75, 0x70646174, 0x655f6c65, 0x64360000,
-0x2b685f75, 0x70646174, 0x655f6c65, 0x64320000,
-0x696e7453, 0x74617465, 0x0, 0x2a2a696e,
-0x69744370, 0x0, 0x23736372, 0x65616d00,
-0x69537461, 0x636b4572, 0x0, 0x70726f62,
-0x654d656d, 0x0, 0x2a2a4441, 0x574e5f42,
-0x0, 0x2b73775f, 0x646d615f, 0x61737369,
-0x73745f70, 0x6c75735f, 0x74696d65, 0x72000000,
-0x2b267072, 0x656c6f61, 0x645f7772, 0x5f646573,
-0x63720000, 0x2b267072, 0x656c6f61, 0x645f7264,
-0x5f646573, 0x63720000, 0x2b685f68, 0x665f7469,
-0x6d657200, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f7469, 0x6d65722e, 0x632c7620, 0x312e312e,
-0x322e3335, 0x20313939, 0x392f3031, 0x2f323720,
-0x31393a30, 0x393a3530, 0x20686179, 0x65732045,
-0x78702024, 0x0, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x542d446d, 0x61526432,
-0x0, 0x542d446d, 0x61526431, 0x0,
-0x542d446d, 0x61526442, 0x0, 0x542d446d,
-0x61577232, 0x0, 0x542d446d, 0x61577231,
-0x0, 0x542d446d, 0x61577242, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f636f, 0x6d6d616e, 0x642e632c, 0x7620312e,
-0x312e322e, 0x32382031, 0x3939392f, 0x30312f32,
-0x30203139, 0x3a34393a, 0x34392073, 0x6875616e,
-0x67204578, 0x70202400, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x3f48636d, 0x644d6278,
-0x0, 0x3f636d64, 0x48737453, 0x0,
-0x3f636d64, 0x4d634d64, 0x0, 0x3f636d64,
-0x50726f6d, 0x0, 0x3f636d64, 0x4c696e6b,
-0x0, 0x3f636d64, 0x45727200, 0x86ac,
-0x8e5c, 0x8e5c, 0x8de4, 0x8b78,
-0x8e30, 0x8e5c, 0x8790, 0x8800,
-0x8990, 0x8a68, 0x8a34, 0x8e5c,
-0x8870, 0x8b24, 0x8e5c, 0x8b34,
-0x87b4, 0x8824, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f6d63, 0x6173742e, 0x632c7620, 0x312e312e,
-0x322e3820, 0x31393938, 0x2f31322f, 0x30382030,
-0x323a3336, 0x3a333620, 0x73687561, 0x6e672045,
-0x78702024, 0x0, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x6164644d, 0x63447570,
-0x0, 0x6164644d, 0x6346756c, 0x0,
-0x64656c4d, 0x634e6f45, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f646d, 0x612e632c, 0x7620312e, 0x312e322e,
-0x32342031, 0x3939382f, 0x31322f32, 0x31203030,
-0x3a33333a, 0x30392073, 0x6875616e, 0x67204578,
-0x70202400, 0x65767452, 0x6e674600, 0x51657674,
-0x46000000, 0x51657674, 0x505f4600, 0x4d657674,
-0x526e6746, 0x0, 0x4d516576, 0x74460000,
-0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46,
-0x0, 0x5173436f, 0x6e734600, 0x51725072,
-0x6f644600, 0x7377446d, 0x614f6666, 0x0,
-0x31446d61, 0x4f6e0000, 0x7377446d, 0x614f6e00,
-0x2372446d, 0x6141544e, 0x0, 0x72446d61,
-0x41544e30, 0x0, 0x72446d61, 0x41544e31,
-0x0, 0x72446d61, 0x34476200, 0x2a50414e,
-0x49432a00, 0x2e2e2f2e, 0x2e2f2e2e, 0x2f2e2e2f,
-0x2e2e2f73, 0x72632f6e, 0x69632f66, 0x77322f63,
-0x6f6d6d6f, 0x6e2f646d, 0x612e6300, 0x2377446d,
-0x6141544e, 0x0, 0x77446d61, 0x41544e30,
-0x0, 0x77446d61, 0x41544e31, 0x0,
-0x77446d61, 0x34476200, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f7472, 0x6163652e, 0x632c7620, 0x312e312e,
-0x322e3520, 0x31393938, 0x2f30392f, 0x33302031,
-0x383a3530, 0x3a323820, 0x73687561, 0x6e672045,
-0x78702024, 0x0, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f6461, 0x74612e63, 0x2c762031, 0x2e312e32,
-0x2e313220, 0x31393939, 0x2f30312f, 0x32302031,
-0x393a3439, 0x3a353120, 0x73687561, 0x6e672045,
-0x78702024, 0x0, 0x46575f56, 0x45525349,
-0x4f4e3a20, 0x23312046, 0x72692041, 0x70722037,
-0x2031373a, 0x35373a35, 0x32205044, 0x54203230,
-0x30300000, 0x46575f43, 0x4f4d5049, 0x4c455f54,
-0x494d453a, 0x2031373a, 0x35373a35, 0x32000000,
-0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064,
-0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049,
-0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465,
-0x0, 0x46575f43, 0x4f4d5049, 0x4c455f44,
-0x4f4d4149, 0x4e3a2065, 0x6e672e61, 0x6374656f,
-0x6e2e636f, 0x6d000000, 0x46575f43, 0x4f4d5049,
-0x4c45523a, 0x20676363, 0x20766572, 0x73696f6e,
-0x20322e37, 0x2e320000, 0x0, 0x12041100,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f6d65, 0x6d2e632c, 0x7620312e, 0x312e322e,
-0x35203139, 0x39382f30, 0x392f3330, 0x2031383a,
-0x35303a30, 0x38207368, 0x75616e67, 0x20457870,
-0x20240000, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f7365, 0x6e642e63, 0x2c762031, 0x2e312e32,
-0x2e343420, 0x31393938, 0x2f31322f, 0x32312030,
-0x303a3333, 0x3a313820, 0x73687561, 0x6e672045,
-0x78702024, 0x0, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x69736e74, 0x54637055,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f7265, 0x63762e63, 0x2c762031, 0x2e312e32,
-0x2e353320, 0x31393939, 0x2f30312f, 0x31362030,
-0x323a3535, 0x3a343320, 0x73687561, 0x6e672045,
-0x78702024, 0x0, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x724d6163, 0x43686b30,
-0x0, 0x72784672, 0x6d324c67, 0x0,
-0x72784e6f, 0x53744264, 0x0, 0x72784e6f,
-0x4d694264, 0x0, 0x72784e6f, 0x4a6d4264,
-0x0, 0x7278436b, 0x446d6146, 0x0,
-0x72785144, 0x6d457846, 0x0, 0x72785144,
-0x6d614600, 0x72785144, 0x4c426446, 0x0,
-0x72785144, 0x6d426446, 0x0, 0x72784372,
-0x63506164, 0x0, 0x72536d51, 0x446d6146,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f6d61, 0x632e632c, 0x7620312e, 0x312e322e,
-0x32322031, 0x3939382f, 0x31322f30, 0x38203032,
-0x3a33363a, 0x33302073, 0x6875616e, 0x67204578,
-0x70202400, 0x65767452, 0x6e674600, 0x51657674,
-0x46000000, 0x51657674, 0x505f4600, 0x4d657674,
-0x526e6746, 0x0, 0x4d516576, 0x74460000,
-0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46,
-0x0, 0x5173436f, 0x6e734600, 0x51725072,
-0x6f644600, 0x6d616354, 0x68726573, 0x0,
-0x23744d61, 0x6341544e, 0x0, 0x23724d61,
-0x6341544e, 0x0, 0x72656d41, 0x73737274,
-0x0, 0x6c696e6b, 0x444f574e, 0x0,
-0x6c696e6b, 0x55500000, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f636b, 0x73756d2e, 0x632c7620, 0x312e312e,
-0x322e3920, 0x31393939, 0x2f30312f, 0x31342030,
-0x303a3033, 0x3a343820, 0x73687561, 0x6e672045,
-0x78702024, 0x0, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x0, 0x0,
-0x0, 0x50726f62, 0x65506879, 0x0,
-0x6c6e6b41, 0x53535254, 0x0, 0x109a4,
-0x10a1c, 0x10a50, 0x10a7c, 0x11050,
-0x10aa8, 0x10b10, 0x111fc, 0x10dc0,
-0x10c68, 0x10c80, 0x10cc4, 0x10cec,
-0x10d0c, 0x10d34, 0x111fc, 0x10dc0,
-0x10df8, 0x10e10, 0x10e40, 0x10e68,
-0x10e88, 0x10eb0, 0x0, 0x10fdc,
-0x11008, 0x1102c, 0x111fc, 0x11050,
-0x11078, 0x11108, 0x0, 0x0,
-0x0, 0x1186c, 0x1193c, 0x11a14,
-0x11ae4, 0x11b40, 0x11c1c, 0x11c44,
-0x11d20, 0x11d48, 0x11ef0, 0x11f18,
-0x120c0, 0x122b8, 0x1254c, 0x12460,
-0x1254c, 0x12578, 0x120e8, 0x12290,
-0x7273745f, 0x676d6969, 0x0, 0x12608,
-0x12640, 0x12728, 0x13374, 0x133b4,
-0x133cc, 0x7365746c, 0x6f6f7000, 0x0,
-0x0, 0x13bbc, 0x13bfc, 0x13c8c,
-0x13cd0, 0x13d34, 0x13dc0, 0x13df4,
-0x13e7c, 0x13f14, 0x13fe4, 0x14024,
-0x140a8, 0x140cc, 0x141dc, 0x646f4261,
-0x73655067, 0x0, 0x0, 0x0,
-0x0, 0x73746d61, 0x634c4e4b, 0x0,
-0x6765746d, 0x636c6e6b, 0x0, 0x14ed8,
-0x14ed8, 0x14b8c, 0x14bd8, 0x14c24,
-0x14ed8, 0x7365746d, 0x61636163, 0x74000000,
-0x0, 0x0 };
-static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __devinitdata = {
-0x1,
-0x1, 0x1, 0xc001fc, 0x3ffc,
-0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49,
-0x43205600, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x416c7465,
-0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242,
-0x0, 0x0, 0x0, 0x1ffffc,
-0x1fff7c, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x60cf00,
-0x60, 0xcf000000, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x3, 0x0,
-0x1, 0x0, 0x0, 0x0,
-0x1, 0x0, 0x1, 0x0,
-0x0, 0x0, 0x0, 0x1,
-0x1, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x1000000, 0x21000000,
-0x12000140, 0x0, 0x0, 0x20000000,
-0x120000a0, 0x0, 0x12000060, 0x12000180,
-0x120001e0, 0x0, 0x0, 0x0,
-0x1, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x2,
-0x0, 0x0, 0x30001, 0x1,
-0x30201, 0x0, 0x0, 0x1010101,
-0x1010100, 0x10100, 0x1010001, 0x10001,
-0x1000101, 0x101, 0x0, 0x0 };
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 187ac6eb6e94..7709992bb6bf 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1813,6 +1813,25 @@ static void __devinit amd8111e_probe_ext_phy(struct net_device* dev)
lp->ext_phy_addr = 1;
}
+static const struct net_device_ops amd8111e_netdev_ops = {
+ .ndo_open = amd8111e_open,
+ .ndo_stop = amd8111e_close,
+ .ndo_start_xmit = amd8111e_start_xmit,
+ .ndo_tx_timeout = amd8111e_tx_timeout,
+ .ndo_get_stats = amd8111e_get_stats,
+ .ndo_set_multicast_list = amd8111e_set_multicast_list,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = amd8111e_set_mac_address,
+ .ndo_do_ioctl = amd8111e_ioctl,
+ .ndo_change_mtu = amd8111e_change_mtu,
+#if AMD8111E_VLAN_TAG_USED
+ .ndo_vlan_rx_register = amd8111e_vlan_rx_register,
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = amd8111e_poll,
+#endif
+};
+
static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -1872,7 +1891,6 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
#if AMD8111E_VLAN_TAG_USED
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX ;
- dev->vlan_rx_register =amd8111e_vlan_rx_register;
#endif
lp = netdev_priv(dev);
@@ -1901,27 +1919,16 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
if(dynamic_ipg[card_idx++])
lp->options |= OPTION_DYN_IPG_ENABLE;
+
/* Initialize driver entry points */
- dev->open = amd8111e_open;
- dev->hard_start_xmit = amd8111e_start_xmit;
- dev->stop = amd8111e_close;
- dev->get_stats = amd8111e_get_stats;
- dev->set_multicast_list = amd8111e_set_multicast_list;
- dev->set_mac_address = amd8111e_set_mac_address;
- dev->do_ioctl = amd8111e_ioctl;
- dev->change_mtu = amd8111e_change_mtu;
+ dev->netdev_ops = &amd8111e_netdev_ops;
SET_ETHTOOL_OPS(dev, &ops);
dev->irq =pdev->irq;
- dev->tx_timeout = amd8111e_tx_timeout;
dev->watchdog_timeo = AMD8111E_TX_TIMEOUT;
netif_napi_add(dev, &lp->napi, amd8111e_rx_poll, 32);
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = amd8111e_poll;
-#endif
#if AMD8111E_VLAN_TAG_USED
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
- dev->vlan_rx_register =amd8111e_vlan_rx_register;
#endif
/* Probe the external PHY */
amd8111e_probe_ext_phy(dev);
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index 9a0be9b2eaad..da64ba88d7f8 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -48,12 +48,18 @@ static int ipddp_mode = IPDDP_DECAP;
/* Index to functions, as function prototypes. */
static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *ipddp_get_stats(struct net_device *dev);
static int ipddp_create(struct ipddp_route *new_rt);
static int ipddp_delete(struct ipddp_route *rt);
static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt);
static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static const struct net_device_ops ipddp_netdev_ops = {
+ .ndo_start_xmit = ipddp_xmit,
+ .ndo_do_ioctl = ipddp_ioctl,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
static struct net_device * __init ipddp_init(void)
{
@@ -61,7 +67,7 @@ static struct net_device * __init ipddp_init(void)
struct net_device *dev;
int err;
- dev = alloc_etherdev(sizeof(struct net_device_stats));
+ dev = alloc_etherdev(0);
if (!dev)
return ERR_PTR(-ENOMEM);
@@ -71,9 +77,7 @@ static struct net_device * __init ipddp_init(void)
printk(version);
/* Initalize the device structure. */
- dev->hard_start_xmit = ipddp_xmit;
- dev->get_stats = ipddp_get_stats;
- dev->do_ioctl = ipddp_ioctl;
+ dev->netdev_ops = &ipddp_netdev_ops;
dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */
dev->mtu = 585;
@@ -103,13 +107,6 @@ static struct net_device * __init ipddp_init(void)
return dev;
}
-/*
- * Get the current statistics. This may be called with the card open or closed.
- */
-static struct net_device_stats *ipddp_get_stats(struct net_device *dev)
-{
- return netdev_priv(dev);
-}
/*
* Transmit LLAP/ELAP frame using aarp_send_ddp.
@@ -170,8 +167,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */
- ((struct net_device_stats *) netdev_priv(dev))->tx_packets++;
- ((struct net_device_stats *) netdev_priv(dev))->tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
dev_kfree_skb(skb);
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
index 6278606d1049..d15d8b79d8e5 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@ -646,6 +646,7 @@ static const struct net_device_ops etherh_netdev_ops = {
.ndo_get_stats = ei_get_stats,
.ndo_set_multicast_list = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_set_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ei_poll,
diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c
index 9ad22d1b00fd..1cf2f949c0b4 100644
--- a/drivers/net/arm/ks8695net.c
+++ b/drivers/net/arm/ks8695net.c
@@ -1357,6 +1357,7 @@ static const struct net_device_ops ks8695_netdev_ops = {
.ndo_start_xmit = ks8695_start_xmit,
.ndo_tx_timeout = ks8695_timeout,
.ndo_set_mac_address = ks8695_set_mac,
+ .ndo_validate_addr = eth_validate_addr,
.ndo_set_multicast_list = ks8695_set_multicast,
};
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index ea493ce23982..4317b3edb3d7 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -204,8 +204,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_id);
static void net_rx(struct net_device *dev);
static void read_block(long ioaddr, int length, unsigned char *buffer, int data_mode);
static int net_close(struct net_device *dev);
-static void set_rx_mode_8002(struct net_device *dev);
-static void set_rx_mode_8012(struct net_device *dev);
+static void set_rx_mode(struct net_device *dev);
static void tx_timeout(struct net_device *dev);
@@ -242,6 +241,17 @@ static int __init atp_init(void)
return -ENODEV;
}
+static const struct net_device_ops atp_netdev_ops = {
+ .ndo_open = net_open,
+ .ndo_stop = net_close,
+ .ndo_start_xmit = atp_send_packet,
+ .ndo_set_multicast_list = set_rx_mode,
+ .ndo_tx_timeout = tx_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
static int __init atp_probe1(long ioaddr)
{
struct net_device *dev = NULL;
@@ -342,12 +352,7 @@ static int __init atp_probe1(long ioaddr)
if (dev->mem_end & 0xf)
net_debug = dev->mem_end & 7;
- dev->open = net_open;
- dev->stop = net_close;
- dev->hard_start_xmit = atp_send_packet;
- dev->set_multicast_list =
- lp->chip_type == RTL8002 ? &set_rx_mode_8002 : &set_rx_mode_8012;
- dev->tx_timeout = tx_timeout;
+ dev->netdev_ops = &atp_netdev_ops;
dev->watchdog_timeo = TX_TIMEOUT;
res = register_netdev(dev);
@@ -903,6 +908,17 @@ static void set_rx_mode_8012(struct net_device *dev)
write_reg(ioaddr, CMR2, CMR2_IRQOUT); /* Switch back to page 0 */
}
+static void set_rx_mode(struct net_device *dev)
+{
+ struct net_local *lp = netdev_priv(dev);
+
+ if (lp->chip_type == RTL8002)
+ return set_rx_mode_8002(dev);
+ else
+ return set_rx_mode_8012(dev);
+}
+
+
static int __init atp_init_module(void) {
if (debug) /* Emit version even if no cards detected. */
printk(KERN_INFO "%s", version);
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index 337488ec707c..a4eb6c40678c 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -37,7 +37,10 @@ static int phy_debug = 0;
#define __ei_open ax_ei_open
#define __ei_close ax_ei_close
#define __ei_poll ax_ei_poll
+#define __ei_start_xmit ax_ei_start_xmit
#define __ei_tx_timeout ax_ei_tx_timeout
+#define __ei_get_stats ax_ei_get_stats
+#define __ei_set_multicast_list ax_ei_set_multicast_list
#define __ei_interrupt ax_ei_interrupt
#define ____alloc_ei_netdev ax__alloc_ei_netdev
#define __NS8390_init ax_NS8390_init
@@ -623,6 +626,23 @@ static void ax_eeprom_register_write(struct eeprom_93cx6 *eeprom)
}
#endif
+static const struct net_device_ops ax_netdev_ops = {
+ .ndo_open = ax_open,
+ .ndo_stop = ax_close,
+ .ndo_do_ioctl = ax_ioctl,
+
+ .ndo_start_xmit = ax_ei_start_xmit,
+ .ndo_tx_timeout = ax_ei_tx_timeout,
+ .ndo_get_stats = ax_ei_get_stats,
+ .ndo_set_multicast_list = ax_ei_set_multicast_list,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_change_mtu = eth_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = ax_ei_poll,
+#endif
+};
+
/* setup code */
static void ax_initial_setup(struct net_device *dev, struct ei_device *ei_local)
@@ -738,9 +758,7 @@ static int ax_init_dev(struct net_device *dev, int first_init)
ei_status.get_8390_hdr = &ax_get_8390_hdr;
ei_status.priv = 0;
- dev->open = ax_open;
- dev->stop = ax_close;
- dev->do_ioctl = ax_ioctl;
+ dev->netdev_ops = &ax_netdev_ops;
dev->ethtool_ops = &ax_ethtool_ops;
ax->msg_enable = NETIF_MSG_LINK;
@@ -753,9 +771,6 @@ static int ax_init_dev(struct net_device *dev, int first_init)
ax->mii.mdio_write = ax_phy_write;
ax->mii.dev = dev;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = ax_ei_poll;
-#endif
ax_NS8390_init(dev, 0);
if (first_init)
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 0e7470a201f0..c38512ebcea6 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -73,8 +73,8 @@
(BP)->tx_cons - (BP)->tx_prod - TX_RING_GAP(BP))
#define NEXT_TX(N) (((N) + 1) & (B44_TX_RING_SIZE - 1))
-#define RX_PKT_OFFSET 30
-#define RX_PKT_BUF_SZ (1536 + RX_PKT_OFFSET + 64)
+#define RX_PKT_OFFSET (RX_HEADER_LEN + 2)
+#define RX_PKT_BUF_SZ (1536 + RX_PKT_OFFSET)
/* minimum number of free TX descriptors required to wake up TX process */
#define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4)
@@ -679,10 +679,10 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
dev_kfree_skb_any(skb);
return -ENOMEM;
}
+ bp->force_copybreak = 1;
}
rh = (struct rx_header *) skb->data;
- skb_reserve(skb, RX_PKT_OFFSET);
rh->len = 0;
rh->flags = 0;
@@ -693,13 +693,13 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
if (src_map != NULL)
src_map->skb = NULL;
- ctrl = (DESC_CTRL_LEN & (RX_PKT_BUF_SZ - RX_PKT_OFFSET));
+ ctrl = (DESC_CTRL_LEN & RX_PKT_BUF_SZ);
if (dest_idx == (B44_RX_RING_SIZE - 1))
ctrl |= DESC_CTRL_EOT;
dp = &bp->rx_ring[dest_idx];
dp->ctrl = cpu_to_le32(ctrl);
- dp->addr = cpu_to_le32((u32) mapping + RX_PKT_OFFSET + bp->dma_offset);
+ dp->addr = cpu_to_le32((u32) mapping + bp->dma_offset);
if (bp->flags & B44_FLAG_RX_RING_HACK)
b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma,
@@ -801,7 +801,7 @@ static int b44_rx(struct b44 *bp, int budget)
/* Omit CRC. */
len -= 4;
- if (len > RX_COPY_THRESHOLD) {
+ if (!bp->force_copybreak && len > RX_COPY_THRESHOLD) {
int skb_size;
skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
if (skb_size < 0)
@@ -809,8 +809,8 @@ static int b44_rx(struct b44 *bp, int budget)
ssb_dma_unmap_single(bp->sdev, map,
skb_size, DMA_FROM_DEVICE);
/* Leave out rx_header */
- skb_put(skb, len + RX_PKT_OFFSET);
- skb_pull(skb, RX_PKT_OFFSET);
+ skb_put(skb, len + RX_PKT_OFFSET);
+ skb_pull(skb, RX_PKT_OFFSET);
} else {
struct sk_buff *copy_skb;
@@ -2108,6 +2108,22 @@ static int __devinit b44_get_invariants(struct b44 *bp)
return err;
}
+static const struct net_device_ops b44_netdev_ops = {
+ .ndo_open = b44_open,
+ .ndo_stop = b44_close,
+ .ndo_start_xmit = b44_start_xmit,
+ .ndo_get_stats = b44_get_stats,
+ .ndo_set_multicast_list = b44_set_rx_mode,
+ .ndo_set_mac_address = b44_set_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_do_ioctl = b44_ioctl,
+ .ndo_tx_timeout = b44_tx_timeout,
+ .ndo_change_mtu = b44_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = b44_poll_controller,
+#endif
+};
+
static int __devinit b44_init_one(struct ssb_device *sdev,
const struct ssb_device_id *ent)
{
@@ -2137,6 +2153,7 @@ static int __devinit b44_init_one(struct ssb_device *sdev,
bp = netdev_priv(dev);
bp->sdev = sdev;
bp->dev = dev;
+ bp->force_copybreak = 0;
bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE);
@@ -2145,20 +2162,9 @@ static int __devinit b44_init_one(struct ssb_device *sdev,
bp->rx_pending = B44_DEF_RX_RING_PENDING;
bp->tx_pending = B44_DEF_TX_RING_PENDING;
- dev->open = b44_open;
- dev->stop = b44_close;
- dev->hard_start_xmit = b44_start_xmit;
- dev->get_stats = b44_get_stats;
- dev->set_multicast_list = b44_set_rx_mode;
- dev->set_mac_address = b44_set_mac_addr;
- dev->do_ioctl = b44_ioctl;
- dev->tx_timeout = b44_tx_timeout;
+ dev->netdev_ops = &b44_netdev_ops;
netif_napi_add(dev, &bp->napi, b44_poll, 64);
dev->watchdog_timeo = B44_TX_TIMEOUT;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = b44_poll_controller;
-#endif
- dev->change_mtu = b44_change_mtu;
dev->irq = sdev->irq;
SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index 7db0c84a7950..e678498de6db 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -395,7 +395,7 @@ struct b44 {
u32 rx_pending;
u32 tx_pending;
u8 phy_addr;
-
+ u8 force_copybreak;
struct mii_if_info mii_if;
};
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index fd705d1295a7..6fcccef4cf3d 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -20,6 +20,11 @@
* (you will need to reboot afterwards) */
/* #define BNX2X_STOP_ON_ERROR */
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+#define BCM_VLAN 1
+#endif
+
+
/* error/debug prints */
#define DRV_MODULE_NAME "bnx2x"
@@ -78,11 +83,6 @@
#endif
-#ifdef NETIF_F_HW_VLAN_TX
-#define BCM_VLAN 1
-#endif
-
-
#define U64_LO(x) (u32)(((u64)(x)) & 0xffffffff)
#define U64_HI(x) (u32)(((u64)(x)) >> 32)
#define HILO_U64(hi, lo) ((((u64)(hi)) << 32) + (lo))
@@ -150,6 +150,9 @@ struct sw_rx_page {
#define PAGES_PER_SGE_SHIFT 0
#define PAGES_PER_SGE (1 << PAGES_PER_SGE_SHIFT)
+#define SGE_PAGE_SIZE PAGE_SIZE
+#define SGE_PAGE_SHIFT PAGE_SHIFT
+#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN(addr)
#define BCM_RX_ETH_PAYLOAD_ALIGN 64
@@ -736,7 +739,7 @@ struct bnx2x {
struct bnx2x_fastpath fp[MAX_CONTEXT];
void __iomem *regview;
void __iomem *doorbells;
-#define BNX2X_DB_SIZE (16*2048)
+#define BNX2X_DB_SIZE (16*BCM_PAGE_SIZE)
struct net_device *dev;
struct pci_dev *pdev;
@@ -801,6 +804,8 @@ struct bnx2x {
#define TPA_ENABLE_FLAG 0x80
#define NO_MCP_FLAG 0x100
#define BP_NOMCP(bp) (bp->flags & NO_MCP_FLAG)
+#define HW_VLAN_TX_FLAG 0x400
+#define HW_VLAN_RX_FLAG 0x800
int func;
#define BP_PORT(bp) (bp->func % PORT_MAX)
@@ -811,7 +816,7 @@ struct bnx2x {
int pm_cap;
int pcie_cap;
- struct work_struct sp_task;
+ struct delayed_work sp_task;
struct work_struct reset_task;
struct timer_list timer;
diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c
index 67de94f1f30e..fefa6ab13064 100644
--- a/drivers/net/bnx2x_link.c
+++ b/drivers/net/bnx2x_link.c
@@ -3359,7 +3359,7 @@ static u8 bnx2x_format_ver(u32 num, u8 *str, u16 len)
u8 shift = 8*4;
u8 digit;
if (len < 10) {
- /* Need more then 10chars for this format */
+ /* Need more than 10chars for this format */
*str_ptr = '\0';
return -EINVAL;
}
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index ef8103b3523e..7c533797c064 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -38,9 +38,7 @@
#include <linux/time.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
-#ifdef NETIF_F_HW_VLAN_TX
- #include <linux/if_vlan.h>
-#endif
+#include <linux/if_vlan.h>
#include <net/ip.h>
#include <net/tcp.h>
#include <net/checksum.h>
@@ -95,6 +93,7 @@ MODULE_PARM_DESC(debug, "default debug msglevel");
module_param(use_multi, int, 0);
MODULE_PARM_DESC(use_multi, "use per-CPU queues");
#endif
+static struct workqueue_struct *bnx2x_wq;
enum bnx2x_board_type {
BCM57710 = 0,
@@ -671,7 +670,8 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
synchronize_irq(bp->pdev->irq);
/* make sure sp_task is not running */
- cancel_work_sync(&bp->sp_task);
+ cancel_delayed_work(&bp->sp_task);
+ flush_workqueue(bnx2x_wq);
}
/* fast path */
@@ -972,7 +972,7 @@ static inline void bnx2x_free_rx_sge(struct bnx2x *bp,
return;
pci_unmap_page(bp->pdev, pci_unmap_addr(sw_buf, mapping),
- BCM_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE);
+ SGE_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE);
__free_pages(page, PAGES_PER_SGE_SHIFT);
sw_buf->page = NULL;
@@ -1000,7 +1000,7 @@ static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp,
if (unlikely(page == NULL))
return -ENOMEM;
- mapping = pci_map_page(bp->pdev, page, 0, BCM_PAGE_SIZE*PAGES_PER_SGE,
+ mapping = pci_map_page(bp->pdev, page, 0, SGE_PAGE_SIZE*PAGES_PER_SGE,
PCI_DMA_FROMDEVICE);
if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
__free_pages(page, PAGES_PER_SGE_SHIFT);
@@ -1096,9 +1096,9 @@ static void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp,
struct eth_fast_path_rx_cqe *fp_cqe)
{
struct bnx2x *bp = fp->bp;
- u16 sge_len = BCM_PAGE_ALIGN(le16_to_cpu(fp_cqe->pkt_len) -
+ u16 sge_len = SGE_PAGE_ALIGN(le16_to_cpu(fp_cqe->pkt_len) -
le16_to_cpu(fp_cqe->len_on_bd)) >>
- BCM_PAGE_SHIFT;
+ SGE_PAGE_SHIFT;
u16 last_max, last_elem, first_elem;
u16 delta = 0;
u16 i;
@@ -1203,22 +1203,22 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
u16 cqe_idx)
{
struct sw_rx_page *rx_pg, old_rx_pg;
- struct page *sge;
u16 len_on_bd = le16_to_cpu(fp_cqe->len_on_bd);
u32 i, frag_len, frag_size, pages;
int err;
int j;
frag_size = le16_to_cpu(fp_cqe->pkt_len) - len_on_bd;
- pages = BCM_PAGE_ALIGN(frag_size) >> BCM_PAGE_SHIFT;
+ pages = SGE_PAGE_ALIGN(frag_size) >> SGE_PAGE_SHIFT;
/* This is needed in order to enable forwarding support */
if (frag_size)
- skb_shinfo(skb)->gso_size = min((u32)BCM_PAGE_SIZE,
+ skb_shinfo(skb)->gso_size = min((u32)SGE_PAGE_SIZE,
max(frag_size, (u32)len_on_bd));
#ifdef BNX2X_STOP_ON_ERROR
- if (pages > 8*PAGES_PER_SGE) {
+ if (pages >
+ min((u32)8, (u32)MAX_SKB_FRAGS) * SGE_PAGE_SIZE * PAGES_PER_SGE) {
BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n",
pages, cqe_idx);
BNX2X_ERR("fp_cqe->pkt_len = %d fp_cqe->len_on_bd = %d\n",
@@ -1234,9 +1234,8 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
/* FW gives the indices of the SGE as if the ring is an array
(meaning that "next" element will consume 2 indices) */
- frag_len = min(frag_size, (u32)(BCM_PAGE_SIZE*PAGES_PER_SGE));
+ frag_len = min(frag_size, (u32)(SGE_PAGE_SIZE*PAGES_PER_SGE));
rx_pg = &fp->rx_page_ring[sge_idx];
- sge = rx_pg->page;
old_rx_pg = *rx_pg;
/* If we fail to allocate a substitute page, we simply stop
@@ -1249,7 +1248,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
/* Unmap the page as we r going to pass it to the stack */
pci_unmap_page(bp->pdev, pci_unmap_addr(&old_rx_pg, mapping),
- BCM_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE);
+ SGE_PAGE_SIZE*PAGES_PER_SGE, PCI_DMA_FROMDEVICE);
/* Add one frag and update the appropriate fields in the skb */
skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len);
@@ -1282,6 +1281,13 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
if (likely(new_skb)) {
/* fix ip xsum and give it to the stack */
/* (no need to map the new skb) */
+#ifdef BCM_VLAN
+ int is_vlan_cqe =
+ (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
+ PARSING_FLAGS_VLAN);
+ int is_not_hwaccel_vlan_cqe =
+ (is_vlan_cqe && (!(bp->flags & HW_VLAN_RX_FLAG)));
+#endif
prefetch(skb);
prefetch(((char *)(skb)) + 128);
@@ -1306,6 +1312,12 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
struct iphdr *iph;
iph = (struct iphdr *)skb->data;
+#ifdef BCM_VLAN
+ /* If there is no Rx VLAN offloading -
+ take VLAN tag into an account */
+ if (unlikely(is_not_hwaccel_vlan_cqe))
+ iph = (struct iphdr *)((u8 *)iph + VLAN_HLEN);
+#endif
iph->check = 0;
iph->check = ip_fast_csum((u8 *)iph, iph->ihl);
}
@@ -1313,9 +1325,8 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
if (!bnx2x_fill_frag_skb(bp, fp, skb,
&cqe->fast_path_cqe, cqe_idx)) {
#ifdef BCM_VLAN
- if ((bp->vlgrp != NULL) &&
- (le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
- PARSING_FLAGS_VLAN))
+ if ((bp->vlgrp != NULL) && is_vlan_cqe &&
+ (!is_not_hwaccel_vlan_cqe))
vlan_hwaccel_receive_skb(skb, bp->vlgrp,
le16_to_cpu(cqe->fast_path_cqe.
vlan_tag));
@@ -1355,11 +1366,23 @@ static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
rx_prods.cqe_prod = rx_comp_prod;
rx_prods.sge_prod = rx_sge_prod;
+ /*
+ * Make sure that the BD and SGE data is updated before updating the
+ * producers since FW might read the BD/SGE right after the producer
+ * is updated.
+ * This is only applicable for weak-ordered memory model archs such
+ * as IA-64. The following barrier is also mandatory since FW will
+ * assumes BDs must have buffers.
+ */
+ wmb();
+
for (i = 0; i < sizeof(struct tstorm_eth_rx_producers)/4; i++)
REG_WR(bp, BAR_TSTRORM_INTMEM +
TSTORM_RX_PRODS_OFFSET(BP_PORT(bp), FP_CL_ID(fp)) + i*4,
((u32 *)&rx_prods)[i]);
+ mmiowb(); /* keep prod updates ordered */
+
DP(NETIF_MSG_RX_STATUS,
"Wrote: bd_prod %u cqe_prod %u sge_prod %u\n",
bd_prod, rx_comp_prod, rx_sge_prod);
@@ -1415,7 +1438,7 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
DP(NETIF_MSG_RX_STATUS, "CQE type %x err %x status %x"
" queue %x vlan %x len %u\n", CQE_TYPE(cqe_fp_flags),
cqe_fp_flags, cqe->fast_path_cqe.status_flags,
- cqe->fast_path_cqe.rss_hash_result,
+ le32_to_cpu(cqe->fast_path_cqe.rss_hash_result),
le16_to_cpu(cqe->fast_path_cqe.vlan_tag),
le16_to_cpu(cqe->fast_path_cqe.pkt_len));
@@ -1547,7 +1570,7 @@ reuse_rx:
}
#ifdef BCM_VLAN
- if ((bp->vlgrp != NULL) &&
+ if ((bp->vlgrp != NULL) && (bp->flags & HW_VLAN_RX_FLAG) &&
(le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) &
PARSING_FLAGS_VLAN))
vlan_hwaccel_receive_skb(skb, bp->vlgrp,
@@ -1580,7 +1603,6 @@ next_cqe:
/* Update producers */
bnx2x_update_rx_prod(bp, fp, bd_prod_fw, sw_comp_prod,
fp->rx_sge_prod);
- mmiowb(); /* keep prod updates ordered */
fp->rx_pkt += rx_pkt;
fp->rx_calls++;
@@ -1660,7 +1682,7 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
if (unlikely(status & 0x1)) {
- schedule_work(&bp->sp_task);
+ queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
status &= ~0x1;
if (!status)
@@ -1887,7 +1909,8 @@ static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode)
static void bnx2x_calc_fc_adv(struct bnx2x *bp)
{
- switch (bp->link_vars.ieee_fc) {
+ switch (bp->link_vars.ieee_fc &
+ MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK) {
case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE:
bp->port.advertising &= ~(ADVERTISED_Asym_Pause |
ADVERTISED_Pause);
@@ -1957,10 +1980,11 @@ static u8 bnx2x_initial_phy_init(struct bnx2x *bp)
rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars);
bnx2x_release_phy_lock(bp);
+ bnx2x_calc_fc_adv(bp);
+
if (bp->link_vars.link_up)
bnx2x_link_report(bp);
- bnx2x_calc_fc_adv(bp);
return rc;
}
@@ -2220,9 +2244,7 @@ static void bnx2x_link_attn(struct bnx2x *bp)
/* Make sure that we are synced with the current statistics */
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
- bnx2x_acquire_phy_lock(bp);
bnx2x_link_update(&bp->link_params, &bp->link_vars);
- bnx2x_release_phy_lock(bp);
if (bp->link_vars.link_up) {
@@ -2471,6 +2493,8 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
if (asserted & ATTN_HARD_WIRED_MASK) {
if (asserted & ATTN_NIG_FOR_FUNC) {
+ bnx2x_acquire_phy_lock(bp);
+
/* save nig interrupt mask */
bp->nig_mask = REG_RD(bp, nig_int_mask_addr);
REG_WR(bp, nig_int_mask_addr, 0);
@@ -2526,8 +2550,10 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
REG_WR(bp, hc_addr, asserted);
/* now set back the mask */
- if (asserted & ATTN_NIG_FOR_FUNC)
+ if (asserted & ATTN_NIG_FOR_FUNC) {
REG_WR(bp, nig_int_mask_addr, bp->nig_mask);
+ bnx2x_release_phy_lock(bp);
+ }
}
static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
@@ -2795,8 +2821,10 @@ static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
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_bits = le32_to_cpu(bp->def_status_blk->atten_status_block.
+ attn_bits);
+ u32 attn_ack = le32_to_cpu(bp->def_status_blk->atten_status_block.
+ attn_bits_ack);
u32 attn_state = bp->attn_state;
/* look for changed bits */
@@ -2820,7 +2848,7 @@ static void bnx2x_attn_int(struct bnx2x *bp)
static void bnx2x_sp_task(struct work_struct *work)
{
- struct bnx2x *bp = container_of(work, struct bnx2x, sp_task);
+ struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work);
u16 status;
@@ -2844,7 +2872,7 @@ static void bnx2x_sp_task(struct work_struct *work)
if (status & 0x2)
bp->stats_pending = 0;
- bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, bp->def_att_idx,
+ bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, le16_to_cpu(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);
@@ -2875,7 +2903,7 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
return IRQ_HANDLED;
#endif
- schedule_work(&bp->sp_task);
+ queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
return IRQ_HANDLED;
}
@@ -2892,7 +2920,7 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
#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; \
+ s_hi += a_hi + ((s_lo < a_lo) ? 1 : 0); \
} while (0)
/* difference = minuend - subtrahend */
@@ -4496,7 +4524,7 @@ static void bnx2x_init_context(struct bnx2x *bp)
static void bnx2x_init_ind_table(struct bnx2x *bp)
{
- int port = BP_PORT(bp);
+ int func = BP_FUNC(bp);
int i;
if (!is_multi(bp))
@@ -4505,10 +4533,8 @@ static void bnx2x_init_ind_table(struct bnx2x *bp)
DP(NETIF_MSG_IFUP, "Initializing indirection table\n");
for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++)
REG_WR8(bp, BAR_TSTRORM_INTMEM +
- TSTORM_INDIRECTION_TABLE_OFFSET(port) + i,
- i % bp->num_queues);
-
- REG_WR(bp, PRS_REG_A_PRSU_20, 0xf);
+ TSTORM_INDIRECTION_TABLE_OFFSET(func) + i,
+ BP_CL_ID(bp) + (i % bp->num_queues));
}
static void bnx2x_set_client_config(struct bnx2x *bp)
@@ -4517,12 +4543,12 @@ static void bnx2x_set_client_config(struct bnx2x *bp)
int port = BP_PORT(bp);
int i;
- tstorm_client.mtu = bp->dev->mtu + ETH_OVREHEAD;
+ tstorm_client.mtu = bp->dev->mtu;
tstorm_client.statistics_counter_id = BP_CL_ID(bp);
tstorm_client.config_flags =
TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE;
#ifdef BCM_VLAN
- if (bp->rx_mode && bp->vlgrp) {
+ if (bp->rx_mode && bp->vlgrp && (bp->flags & HW_VLAN_RX_FLAG)) {
tstorm_client.config_flags |=
TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE;
DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
@@ -4531,7 +4557,7 @@ static void bnx2x_set_client_config(struct bnx2x *bp)
if (bp->flags & TPA_ENABLE_FLAG) {
tstorm_client.max_sges_for_packet =
- BCM_PAGE_ALIGN(tstorm_client.mtu) >> BCM_PAGE_SHIFT;
+ SGE_PAGE_ALIGN(tstorm_client.mtu) >> SGE_PAGE_SHIFT;
tstorm_client.max_sges_for_packet =
((tstorm_client.max_sges_for_packet +
PAGES_PER_SGE - 1) & (~(PAGES_PER_SGE - 1))) >>
@@ -4714,10 +4740,11 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
bp->e1hov);
}
- /* Init CQ ring mapping and aggregation size */
- max_agg_size = min((u32)(bp->rx_buf_size +
- 8*BCM_PAGE_SIZE*PAGES_PER_SGE),
- (u32)0xffff);
+ /* Init CQ ring mapping and aggregation size, the FW limit is 8 frags */
+ max_agg_size =
+ min((u32)(min((u32)8, (u32)MAX_SKB_FRAGS) *
+ SGE_PAGE_SIZE * PAGES_PER_SGE),
+ (u32)0xffff);
for_each_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
@@ -4785,6 +4812,15 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
bnx2x_init_context(bp);
bnx2x_init_internal(bp, load_code);
bnx2x_init_ind_table(bp);
+ bnx2x_stats_init(bp);
+
+ /* At this point, we are ready for interrupts */
+ atomic_set(&bp->intr_sem, 0);
+
+ /* flush all before enabling interrupts */
+ mb();
+ mmiowb();
+
bnx2x_int_enable(bp);
}
@@ -5134,7 +5170,6 @@ static int bnx2x_init_common(struct bnx2x *bp)
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);
@@ -5212,6 +5247,7 @@ static int bnx2x_init_common(struct bnx2x *bp)
}
bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END);
+ REG_WR(bp, PRS_REG_A_PRSU_20, 0xf);
/* set NIC mode */
REG_WR(bp, PRS_REG_NIC_MODE, 1);
if (CHIP_IS_E1H(bp))
@@ -6393,17 +6429,8 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
}
}
- bnx2x_stats_init(bp);
-
bp->state = BNX2X_STATE_OPENING_WAIT4_PORT;
- /* Enable Rx interrupt handling before sending the ramrod
- as it's completed on Rx FP queue */
- bnx2x_napi_enable(bp);
-
- /* Enable interrupt handling */
- atomic_set(&bp->intr_sem, 0);
-
rc = bnx2x_setup_leading(bp);
if (rc) {
BNX2X_ERR("Setup leading failed!\n");
@@ -7501,7 +7528,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
mutex_init(&bp->port.phy_mutex);
- INIT_WORK(&bp->sp_task, bnx2x_sp_task);
+ INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
INIT_WORK(&bp->reset_task, bnx2x_reset_task);
rc = bnx2x_get_hwinfo(bp);
@@ -8243,6 +8270,9 @@ static int bnx2x_set_eeprom(struct net_device *dev,
struct bnx2x *bp = netdev_priv(dev);
int rc;
+ if (!netif_running(dev))
+ return -EAGAIN;
+
DP(BNX2X_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,
@@ -8724,6 +8754,8 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up)
tx_bd->general_data = ((UNICAST_ADDRESS <<
ETH_TX_BD_ETH_ADDR_TYPE_SHIFT) | 1);
+ wmb();
+
fp->hw_tx_prods->bds_prod =
cpu_to_le16(le16_to_cpu(fp->hw_tx_prods->bds_prod) + 1);
mb(); /* FW restriction: must not reorder writing nbd and packets */
@@ -8775,7 +8807,6 @@ test_loopback_rx_exit:
/* Update producers */
bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod,
fp->rx_sge_prod);
- mmiowb(); /* keep prod updates ordered */
test_loopback_exit:
bp->link_params.loopback_mode = LOOPBACK_NONE;
@@ -9546,11 +9577,14 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
"sending pkt %u @%p next_idx %u bd %u @%p\n",
pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_bd);
- if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb)) {
+#ifdef BCM_VLAN
+ if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb) &&
+ (bp->flags & HW_VLAN_TX_FLAG)) {
tx_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb));
tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG;
vlan_off += 4;
} else
+#endif
tx_bd->vlan = cpu_to_le16(pkt_prod);
if (xmit_type) {
@@ -9702,6 +9736,15 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %d bd %u\n", nbd, bd_prod);
+ /*
+ * Make sure that the BD data is updated before updating the producer
+ * since FW might read the BD right after the producer is updated.
+ * This is only applicable for weak-ordered memory model archs such
+ * as IA-64. The following barrier is also mandatory since FW will
+ * assumes packets must have BDs.
+ */
+ wmb();
+
fp->hw_tx_prods->bds_prod =
cpu_to_le16(le16_to_cpu(fp->hw_tx_prods->bds_prod) + nbd);
mb(); /* FW restriction: must not reorder writing nbd and packets */
@@ -9715,6 +9758,9 @@ static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) {
+ /* We want bnx2x_tx_int to "see" the updated tx_bd_prod
+ if we put Tx into XOFF state. */
+ smp_mb();
netif_stop_queue(dev);
bp->eth_stats.driver_xoff++;
if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)
@@ -9984,6 +10030,16 @@ static void bnx2x_vlan_rx_register(struct net_device *dev,
struct bnx2x *bp = netdev_priv(dev);
bp->vlgrp = vlgrp;
+
+ /* Set flags according to the required capabilities */
+ bp->flags &= ~(HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
+
+ if (dev->features & NETIF_F_HW_VLAN_TX)
+ bp->flags |= HW_VLAN_TX_FLAG;
+
+ if (dev->features & NETIF_F_HW_VLAN_RX)
+ bp->flags |= HW_VLAN_RX_FLAG;
+
if (netif_running(dev))
bnx2x_set_client_config(bp);
}
@@ -10140,6 +10196,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
dev->features |= NETIF_F_HIGHDMA;
#ifdef BCM_VLAN
dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
+ bp->flags |= (HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
#endif
dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
dev->features |= NETIF_F_TSO6;
@@ -10516,12 +10573,20 @@ static struct pci_driver bnx2x_pci_driver = {
static int __init bnx2x_init(void)
{
+ bnx2x_wq = create_singlethread_workqueue("bnx2x");
+ if (bnx2x_wq == NULL) {
+ printk(KERN_ERR PFX "Cannot create workqueue\n");
+ return -ENOMEM;
+ }
+
return pci_register_driver(&bnx2x_pci_driver);
}
static void __exit bnx2x_cleanup(void)
{
pci_unregister_driver(&bnx2x_pci_driver);
+
+ destroy_workqueue(bnx2x_wq);
}
module_init(bnx2x_init);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 460c2cad2755..9fb388388fb7 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4148,7 +4148,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
bond_for_each_slave(bond, slave, i) {
pr_debug("s %p s->p %p c_m %p\n", slave,
- slave->prev, slave->dev->change_mtu);
+ slave->prev, slave->dev->netdev_ops->ndo_change_mtu);
res = dev_set_mtu(slave->dev, new_mtu);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 321f43d9f0e2..840b3d1a22f5 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -4977,6 +4977,22 @@ static void __devinit cas_program_bridge(struct pci_dev *cas_pdev)
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xff);
}
+static const struct net_device_ops cas_netdev_ops = {
+ .ndo_open = cas_open,
+ .ndo_stop = cas_close,
+ .ndo_start_xmit = cas_start_xmit,
+ .ndo_get_stats = cas_get_stats,
+ .ndo_set_multicast_list = cas_set_multicast,
+ .ndo_do_ioctl = cas_ioctl,
+ .ndo_tx_timeout = cas_tx_timeout,
+ .ndo_change_mtu = cas_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = cas_netpoll,
+#endif
+};
+
static int __devinit cas_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -5166,22 +5182,13 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
for (i = 0; i < N_RX_FLOWS; i++)
skb_queue_head_init(&cp->rx_flows[i]);
- dev->open = cas_open;
- dev->stop = cas_close;
- dev->hard_start_xmit = cas_start_xmit;
- dev->get_stats = cas_get_stats;
- dev->set_multicast_list = cas_set_multicast;
- dev->do_ioctl = cas_ioctl;
+ dev->netdev_ops = &cas_netdev_ops;
dev->ethtool_ops = &cas_ethtool_ops;
- dev->tx_timeout = cas_tx_timeout;
dev->watchdog_timeo = CAS_TX_TIMEOUT;
- dev->change_mtu = cas_change_mtu;
+
#ifdef USE_NAPI
netif_napi_add(dev, &cp->napi, cas_poll, 64);
#endif
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = cas_netpoll;
-#endif
dev->irq = pdev->irq;
dev->dma = 0;
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 5b346f9eaa8b..a89d8cc51205 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -50,12 +50,17 @@ struct vlan_group;
struct adapter;
struct sge_qset;
+enum { /* rx_offload flags */
+ T3_RX_CSUM = 1 << 0,
+ T3_LRO = 1 << 1,
+};
+
struct port_info {
struct adapter *adapter;
struct vlan_group *vlan_grp;
struct sge_qset *qs;
u8 port_id;
- u8 rx_csum_offload;
+ u8 rx_offload;
u8 nqsets;
u8 first_qset;
struct cphy phy;
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 2847f947499d..0089746b8d02 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -546,7 +546,7 @@ static int setup_sge_qsets(struct adapter *adap)
pi->qs = &adap->sge.qs[pi->first_qset];
for (j = pi->first_qset; j < pi->first_qset + pi->nqsets;
++j, ++qset_idx) {
- set_qset_lro(dev, qset_idx, pi->rx_csum_offload);
+ set_qset_lro(dev, qset_idx, pi->rx_offload & T3_LRO);
err = t3_sge_alloc_qset(adap, qset_idx, 1,
(adap->flags & USING_MSIX) ? qset_idx + 1 :
irq_idx,
@@ -1657,17 +1657,19 @@ static u32 get_rx_csum(struct net_device *dev)
{
struct port_info *p = netdev_priv(dev);
- return p->rx_csum_offload;
+ return p->rx_offload & T3_RX_CSUM;
}
static int set_rx_csum(struct net_device *dev, u32 data)
{
struct port_info *p = netdev_priv(dev);
- p->rx_csum_offload = data;
- if (!data) {
+ if (data) {
+ p->rx_offload |= T3_RX_CSUM;
+ } else {
int i;
+ p->rx_offload &= ~(T3_RX_CSUM | T3_LRO);
for (i = p->first_qset; i < p->first_qset + p->nqsets; i++)
set_qset_lro(dev, i, 0);
}
@@ -1830,15 +1832,18 @@ static int cxgb3_set_flags(struct net_device *dev, u32 data)
int i;
if (data & ETH_FLAG_LRO) {
- if (!pi->rx_csum_offload)
+ if (!(pi->rx_offload & T3_RX_CSUM))
return -EINVAL;
+ pi->rx_offload |= T3_LRO;
for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++)
set_qset_lro(dev, i, 1);
- } else
+ } else {
+ pi->rx_offload &= ~T3_LRO;
for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++)
set_qset_lro(dev, i, 0);
+ }
return 0;
}
@@ -1926,7 +1931,7 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
pi = adap2pinfo(adapter, i);
if (t.qset_idx >= pi->first_qset &&
t.qset_idx < pi->first_qset + pi->nqsets &&
- !pi->rx_csum_offload)
+ !(pi->rx_offload & T3_RX_CSUM))
return -EINVAL;
}
@@ -2946,7 +2951,7 @@ static int __devinit init_one(struct pci_dev *pdev,
adapter->port[i] = netdev;
pi = netdev_priv(netdev);
pi->adapter = adapter;
- pi->rx_csum_offload = 1;
+ pi->rx_offload = T3_RX_CSUM | T3_LRO;
pi->port_id = i;
netif_carrier_off(netdev);
netif_tx_stop_all_queues(netdev);
@@ -2955,6 +2960,7 @@ static int __devinit init_one(struct pci_dev *pdev,
netdev->mem_end = mmio_start + mmio_len - 1;
netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
netdev->features |= NETIF_F_LLTX;
+ netdev->features |= NETIF_F_LRO;
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 6c641a889471..14f9fb3e8795 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -1932,7 +1932,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
skb_pull(skb, sizeof(*p) + pad);
skb->protocol = eth_type_trans(skb, adap->port[p->iff]);
pi = netdev_priv(skb->dev);
- if (pi->rx_csum_offload && p->csum_valid && p->csum == htons(0xffff) &&
+ if ((pi->rx_offload & T3_RX_CSUM) && p->csum_valid && p->csum == htons(0xffff) &&
!p->fragment) {
qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
skb->ip_summed = CHECKSUM_UNNECESSARY;
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index 970f820ba814..de63f1d41d32 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -378,6 +378,16 @@ static void de600_rx_intr(struct net_device *dev)
*/
}
+static const struct net_device_ops de600_netdev_ops = {
+ .ndo_open = de600_open,
+ .ndo_stop = de600_close,
+ .ndo_start_xmit = de600_start_xmit,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+
static struct net_device * __init de600_probe(void)
{
int i;
@@ -439,9 +449,7 @@ static struct net_device * __init de600_probe(void)
printk(", Ethernet Address: %pM\n", dev->dev_addr);
- dev->open = de600_open;
- dev->stop = de600_close;
- dev->hard_start_xmit = &de600_start_xmit;
+ dev->netdev_ops = &de600_netdev_ops;
dev->flags&=~IFF_MULTICAST;
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index bdfa89403389..d52f34cc9526 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -784,6 +784,17 @@ static int adapter_init(struct net_device *dev)
return 0; /* all ok */
}
+static const struct net_device_ops de620_netdev_ops = {
+ .ndo_open = de620_open,
+ .ndo_stop = de620_close,
+ .ndo_start_xmit = de620_start_xmit,
+ .ndo_tx_timeout = de620_timeout,
+ .ndo_set_multicast_list = de620_set_multicast_list,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
/******************************************************************************
*
* Only start-up code below
@@ -861,12 +872,8 @@ struct net_device * __init de620_probe(int unit)
else
printk(" UTP)\n");
- dev->open = de620_open;
- dev->stop = de620_close;
- dev->hard_start_xmit = de620_start_xmit;
- dev->tx_timeout = de620_timeout;
+ dev->netdev_ops = &de620_netdev_ops;
dev->watchdog_timeo = HZ*2;
- dev->set_multicast_list = de620_set_multicast_list;
/* base_addr and irq are already set, see above! */
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 134b2d60b479..86bb876fb123 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -161,6 +161,7 @@
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <linux/string.h>
+#include <linux/firmware.h>
#include <asm/unaligned.h>
@@ -174,10 +175,17 @@
#define E100_WATCHDOG_PERIOD (2 * HZ)
#define E100_NAPI_WEIGHT 16
+#define FIRMWARE_D101M "e100/d101m_ucode.bin"
+#define FIRMWARE_D101S "e100/d101s_ucode.bin"
+#define FIRMWARE_D102E "e100/d102e_ucode.bin"
+
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+MODULE_FIRMWARE(FIRMWARE_D101M);
+MODULE_FIRMWARE(FIRMWARE_D101S);
+MODULE_FIRMWARE(FIRMWARE_D102E);
static int debug = 3;
static int eeprom_bad_csum_allow = 0;
@@ -1049,178 +1057,6 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
}
-/********************************************************/
-/* Micro code for 8086:1229 Rev 8 */
-/********************************************************/
-
-/* Parameter values for the D101M B-step */
-#define D101M_CPUSAVER_TIMER_DWORD 78
-#define D101M_CPUSAVER_BUNDLE_DWORD 65
-#define D101M_CPUSAVER_MIN_SIZE_DWORD 126
-
-#define D101M_B_RCVBUNDLE_UCODE \
-{\
-0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \
-0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \
-0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \
-0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \
-0x00380438, 0x00000000, 0x00140000, 0x00380555, \
-0x00308000, 0x00100662, 0x00100561, 0x000E0408, \
-0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
-0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
-0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \
-0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \
-0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \
-0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \
-0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \
-0x00041000, 0x00010004, 0x00130826, 0x000C0006, \
-0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
-0x00101210, 0x00380C34, 0x00000000, 0x00000000, \
-0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \
-0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \
-0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \
-0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \
-0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \
-0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \
-0x00130826, 0x000C0001, 0x00220559, 0x00101313, \
-0x00380559, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00130831, 0x0010090B, 0x00124813, \
-0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \
-0x003806A8, 0x00000000, 0x00000000, 0x00000000, \
-}
-
-/********************************************************/
-/* Micro code for 8086:1229 Rev 9 */
-/********************************************************/
-
-/* Parameter values for the D101S */
-#define D101S_CPUSAVER_TIMER_DWORD 78
-#define D101S_CPUSAVER_BUNDLE_DWORD 67
-#define D101S_CPUSAVER_MIN_SIZE_DWORD 128
-
-#define D101S_RCVBUNDLE_UCODE \
-{\
-0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \
-0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \
-0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \
-0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \
-0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \
-0x00308000, 0x00100610, 0x00100561, 0x000E0408, \
-0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
-0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
-0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \
-0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \
-0x003A047E, 0x00044010, 0x00380819, 0x00000000, \
-0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \
-0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \
-0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \
-0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \
-0x00101313, 0x00380700, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
-0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \
-0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \
-0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \
-0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \
-0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \
-0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \
-0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \
-0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \
-0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00130831, \
-0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \
-0x00041000, 0x00010004, 0x00380700 \
-}
-
-/********************************************************/
-/* Micro code for the 8086:1229 Rev F/10 */
-/********************************************************/
-
-/* Parameter values for the D102 E-step */
-#define D102_E_CPUSAVER_TIMER_DWORD 42
-#define D102_E_CPUSAVER_BUNDLE_DWORD 54
-#define D102_E_CPUSAVER_MIN_SIZE_DWORD 46
-
-#define D102_E_RCVBUNDLE_UCODE \
-{\
-0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x0EF70E36, 0x1FFF1FFF, \
-0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \
-0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \
-0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \
-0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \
-0x00300006, 0x00E014FB, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00000000, 0x00000000, 0x00000000, 0x00000000, \
-0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000, \
-0x00906EFD, 0x00900EFD, 0x00E00EF8, 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, \
-}
-
-static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb)
-{
-/* *INDENT-OFF* */
- static struct {
- u32 ucode[UCODE_SIZE + 1];
- u8 mac;
- u8 timer_dword;
- u8 bundle_dword;
- u8 min_size_dword;
- } ucode_opts[] = {
- { D101M_B_RCVBUNDLE_UCODE,
- mac_82559_D101M,
- D101M_CPUSAVER_TIMER_DWORD,
- D101M_CPUSAVER_BUNDLE_DWORD,
- D101M_CPUSAVER_MIN_SIZE_DWORD },
- { D101S_RCVBUNDLE_UCODE,
- mac_82559_D101S,
- D101S_CPUSAVER_TIMER_DWORD,
- D101S_CPUSAVER_BUNDLE_DWORD,
- D101S_CPUSAVER_MIN_SIZE_DWORD },
- { D102_E_RCVBUNDLE_UCODE,
- mac_82551_F,
- D102_E_CPUSAVER_TIMER_DWORD,
- D102_E_CPUSAVER_BUNDLE_DWORD,
- D102_E_CPUSAVER_MIN_SIZE_DWORD },
- { D102_E_RCVBUNDLE_UCODE,
- mac_82551_10,
- D102_E_CPUSAVER_TIMER_DWORD,
- D102_E_CPUSAVER_BUNDLE_DWORD,
- D102_E_CPUSAVER_MIN_SIZE_DWORD },
- { {0}, 0, 0, 0, 0}
- }, *opts;
-/* *INDENT-ON* */
-
/*************************************************************************
* CPUSaver parameters
*
@@ -1280,42 +1116,101 @@ static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb
#define BUNDLEMAX (u16)6
#define INTDELAY (u16)1536 /* 0x600 */
+/* Initialize firmware */
+static const struct firmware *e100_request_firmware(struct nic *nic)
+{
+ const char *fw_name;
+ const struct firmware *fw;
+ u8 timer, bundle, min_size;
+ int err;
+
/* do not load u-code for ICH devices */
if (nic->flags & ich)
- goto noloaducode;
+ return NULL;
/* Search for ucode match against h/w revision */
- for (opts = ucode_opts; opts->mac; opts++) {
- int i;
- u32 *ucode = opts->ucode;
- if (nic->mac != opts->mac)
- continue;
-
- /* Insert user-tunable settings */
- ucode[opts->timer_dword] &= 0xFFFF0000;
- ucode[opts->timer_dword] |= INTDELAY;
- ucode[opts->bundle_dword] &= 0xFFFF0000;
- ucode[opts->bundle_dword] |= BUNDLEMAX;
- ucode[opts->min_size_dword] &= 0xFFFF0000;
- ucode[opts->min_size_dword] |= (BUNDLESMALL) ? 0xFFFF : 0xFF80;
-
- for (i = 0; i < UCODE_SIZE; i++)
- cb->u.ucode[i] = cpu_to_le32(ucode[i]);
- cb->command = cpu_to_le16(cb_ucode | cb_el);
- return;
- }
-
-noloaducode:
- cb->command = cpu_to_le16(cb_nop | cb_el);
-}
-
-static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb,
- void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *))
-{
+ if (nic->mac == mac_82559_D101M)
+ fw_name = FIRMWARE_D101M;
+ else if (nic->mac == mac_82559_D101S)
+ fw_name = FIRMWARE_D101S;
+ else if (nic->mac == mac_82551_F || nic->mac == mac_82551_10)
+ fw_name = FIRMWARE_D102E;
+ else /* No ucode on other devices */
+ return NULL;
+
+ err = request_firmware(&fw, fw_name, &nic->pdev->dev);
+ if (err) {
+ DPRINTK(PROBE, ERR, "Failed to load firmware \"%s\": %d\n",
+ fw_name, err);
+ return ERR_PTR(err);
+ }
+ /* Firmware should be precisely UCODE_SIZE (words) plus three bytes
+ indicating the offsets for BUNDLESMALL, BUNDLEMAX, INTDELAY */
+ if (fw->size != UCODE_SIZE * 4 + 3) {
+ DPRINTK(PROBE, ERR, "Firmware \"%s\" has wrong size %zu\n",
+ fw_name, fw->size);
+ release_firmware(fw);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* Read timer, bundle and min_size from end of firmware blob */
+ timer = fw->data[UCODE_SIZE * 4];
+ bundle = fw->data[UCODE_SIZE * 4 + 1];
+ min_size = fw->data[UCODE_SIZE * 4 + 2];
+
+ if (timer >= UCODE_SIZE || bundle >= UCODE_SIZE ||
+ min_size >= UCODE_SIZE) {
+ DPRINTK(PROBE, ERR,
+ "\"%s\" has bogus offset values (0x%x,0x%x,0x%x)\n",
+ fw_name, timer, bundle, min_size);
+ release_firmware(fw);
+ return ERR_PTR(-EINVAL);
+ }
+ /* OK, firmware is validated and ready to use... */
+ return fw;
+}
+
+static void e100_setup_ucode(struct nic *nic, struct cb *cb,
+ struct sk_buff *skb)
+{
+ const struct firmware *fw = (void *)skb;
+ u8 timer, bundle, min_size;
+
+ /* It's not a real skb; we just abused the fact that e100_exec_cb
+ will pass it through to here... */
+ cb->skb = NULL;
+
+ /* firmware is stored as little endian already */
+ memcpy(cb->u.ucode, fw->data, UCODE_SIZE * 4);
+
+ /* Read timer, bundle and min_size from end of firmware blob */
+ timer = fw->data[UCODE_SIZE * 4];
+ bundle = fw->data[UCODE_SIZE * 4 + 1];
+ min_size = fw->data[UCODE_SIZE * 4 + 2];
+
+ /* Insert user-tunable settings in cb->u.ucode */
+ cb->u.ucode[timer] &= cpu_to_le32(0xFFFF0000);
+ cb->u.ucode[timer] |= cpu_to_le32(INTDELAY);
+ cb->u.ucode[bundle] &= cpu_to_le32(0xFFFF0000);
+ cb->u.ucode[bundle] |= cpu_to_le32(BUNDLEMAX);
+ cb->u.ucode[min_size] &= cpu_to_le32(0xFFFF0000);
+ cb->u.ucode[min_size] |= cpu_to_le32((BUNDLESMALL) ? 0xFFFF : 0xFF80);
+
+ cb->command = cpu_to_le16(cb_ucode | cb_el);
+}
+
+static inline int e100_load_ucode_wait(struct nic *nic)
+{
+ const struct firmware *fw;
int err = 0, counter = 50;
struct cb *cb = nic->cb_to_clean;
- if ((err = e100_exec_cb(nic, NULL, e100_setup_ucode)))
+ fw = e100_request_firmware(nic);
+ /* If it's NULL, then no ucode is required */
+ if (!fw || IS_ERR(fw))
+ return PTR_ERR(fw);
+
+ if ((err = e100_exec_cb(nic, (void *)fw, e100_setup_ucode)))
DPRINTK(PROBE,ERR, "ucode cmd failed with error %d\n", err);
/* must restart cuc */
@@ -1435,7 +1330,7 @@ static int e100_hw_init(struct nic *nic)
return err;
if ((err = e100_exec_cmd(nic, ruc_load_base, 0)))
return err;
- if ((err = e100_exec_cb_wait(nic, NULL, e100_setup_ucode)))
+ if ((err = e100_load_ucode_wait(nic)))
return err;
if ((err = e100_exec_cb(nic, NULL, e100_configure)))
return err;
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index d04eef53571e..e1a3fc1303ee 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -6758,7 +6758,7 @@ static s32 e1000_get_cable_length(struct e1000_hw *hw, u16 *min_length,
* returns: - E1000_ERR_XXX
* E1000_SUCCESS
*
- * For phy's older then IGP, this function simply reads the polarity bit in the
+ * For phy's older than IGP, this function simply reads the polarity bit in the
* Phy Status register. For IGP phy's, this bit is valid only if link speed is
* 10 Mbps. If the link speed is 100 Mbps there is no polarity so this bit will
* return 0. If the link speed is 1000 Mbps the polarity status is in the
@@ -6834,7 +6834,7 @@ static s32 e1000_check_polarity(struct e1000_hw *hw,
* returns: - E1000_ERR_XXX
* E1000_SUCCESS
*
- * For phy's older then IGP, this function reads the Downshift bit in the Phy
+ * For phy's older than IGP, this function reads the Downshift bit in the Phy
* Specific Status register. For IGP phy's, it reads the Downgrade bit in the
* Link Health register. In IGP this bit is latched high, so the driver must
* read it immediately after link is established.
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index f2a5963b5a95..e415e81ecd3e 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -390,7 +390,8 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
}
static DEFINE_MUTEX(nvm_mutex);
-static pid_t nvm_owner = -1;
+static pid_t nvm_owner_pid = -1;
+static char nvm_owner_name[TASK_COMM_LEN] = "";
/**
* e1000_acquire_swflag_ich8lan - Acquire software control flag
@@ -408,11 +409,15 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
might_sleep();
if (!mutex_trylock(&nvm_mutex)) {
- WARN(1, KERN_ERR "e1000e mutex contention. Owned by pid %d\n",
- nvm_owner);
+ WARN(1, KERN_ERR "e1000e mutex contention. Owned by process "
+ "%s (pid %d), required by process %s (pid %d)\n",
+ nvm_owner_name, nvm_owner_pid,
+ current->comm, current->pid);
+
mutex_lock(&nvm_mutex);
}
- nvm_owner = current->pid;
+ nvm_owner_pid = current->pid;
+ strncpy(nvm_owner_name, current->comm, TASK_COMM_LEN);
while (timeout) {
extcnf_ctrl = er32(EXTCNF_CTRL);
@@ -430,7 +435,8 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
hw_dbg(hw, "FW or HW has locked the resource for too long.\n");
extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
ew32(EXTCNF_CTRL, extcnf_ctrl);
- nvm_owner = -1;
+ nvm_owner_pid = -1;
+ strcpy(nvm_owner_name, "");
mutex_unlock(&nvm_mutex);
return -E1000_ERR_CONFIG;
}
@@ -454,7 +460,8 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
ew32(EXTCNF_CTRL, extcnf_ctrl);
- nvm_owner = -1;
+ nvm_owner_pid = -1;
+ strcpy(nvm_owner_name, "");
mutex_unlock(&nvm_mutex);
}
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index d4639facd1bd..91817d0afcaf 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -4807,7 +4807,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
}
}
- err = pci_request_selected_regions(pdev,
+ err = pci_request_selected_regions_exclusive(pdev,
pci_select_bars(pdev, IORESOURCE_MEM),
e1000e_driver_name);
if (err)
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index 20eb05cddb83..b07ba1924de0 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -169,6 +169,7 @@ static const struct net_device_ops e21_netdev_ops = {
.ndo_get_stats = ei_get_stats,
.ndo_set_multicast_list = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ei_poll,
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index e3131ea629cd..dfe92264e825 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -132,7 +132,7 @@ void ehea_dump(void *adr, int len, char *msg)
int x;
unsigned char *deb = adr;
for (x = 0; x < len; x += 16) {
- printk(DRV_NAME " %s adr=%p ofs=%04x %016lx %016lx\n", msg,
+ printk(DRV_NAME " %s adr=%p ofs=%04x %016llx %016llx\n", msg,
deb, x, *((u64 *)&deb[0]), *((u64 *)&deb[8]));
deb += 16;
}
@@ -883,7 +883,7 @@ static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
while (eqe) {
qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry);
- ehea_error("QP aff_err: entry=0x%lx, token=0x%x",
+ ehea_error("QP aff_err: entry=0x%llx, token=0x%x",
eqe->entry, qp_token);
qp = port->port_res[qp_token].qp;
@@ -1159,7 +1159,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
netif_stop_queue(port->netdev);
break;
default:
- ehea_error("unknown event code %x, eqe=0x%lX", ec, eqe);
+ ehea_error("unknown event code %x, eqe=0x%llX", ec, eqe);
break;
}
}
@@ -1971,7 +1971,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
}
if (dev->mc_count > port->adapter->max_mc_mac) {
- ehea_info("Mcast registration limit reached (0x%lx). "
+ ehea_info("Mcast registration limit reached (0x%llx). "
"Use ALLMULTI!",
port->adapter->max_mc_mac);
goto out;
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
index 2a33a613d9e6..8fe9dcaa7538 100644
--- a/drivers/net/ehea/ehea_phyp.c
+++ b/drivers/net/ehea/ehea_phyp.c
@@ -214,7 +214,7 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
u64 *qp_handle, struct h_epas *h_epas)
{
u64 hret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
u64 allocate_controls =
EHEA_BMASK_SET(H_ALL_RES_QP_EQPO, init_attr->low_lat_rq1 ? 1 : 0)
@@ -312,7 +312,7 @@ u64 ehea_h_alloc_resource_cq(const u64 adapter_handle,
u64 *cq_handle, struct h_epas *epas)
{
u64 hret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
outs,
@@ -374,7 +374,7 @@ u64 ehea_h_alloc_resource_eq(const u64 adapter_handle,
struct ehea_eq_attr *eq_attr, u64 *eq_handle)
{
u64 hret, allocate_controls;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
/* resource type */
allocate_controls =
@@ -407,7 +407,7 @@ u64 ehea_h_modify_ehea_qp(const u64 adapter_handle, const u8 cat,
u16 *out_swr, u16 *out_rwr)
{
u64 hret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
hret = ehea_plpar_hcall9(H_MODIFY_HEA_QP,
outs,
@@ -449,7 +449,7 @@ u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle,
struct ehea_mr *mr)
{
u64 hret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
hret = ehea_plpar_hcall9(H_REGISTER_SMR,
outs,
@@ -468,7 +468,7 @@ u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle,
u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle)
{
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
return ehea_plpar_hcall9(H_DISABLE_AND_GET_HEA,
outs,
@@ -493,7 +493,7 @@ u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
const u32 pd, u64 *mr_handle, u32 *lkey)
{
u64 hret;
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
outs,
@@ -564,7 +564,7 @@ u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num,
const u8 cb_cat, const u64 select_mask,
void *cb_addr)
{
- u64 outs[PLPAR_HCALL9_BUFSIZE];
+ unsigned long outs[PLPAR_HCALL9_BUFSIZE];
u64 port_info;
u64 arr_index = 0;
u64 cb_logaddr = virt_to_abs(cb_addr);
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index 225c692b5d99..49d766ebbcf4 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -168,7 +168,7 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
cq->fw_handle, rpage, 1);
if (hret < H_SUCCESS) {
ehea_error("register_rpage_cq failed ehea_cq=%p "
- "hret=%lx counter=%i act_pages=%i",
+ "hret=%llx counter=%i act_pages=%i",
cq, hret, counter, cq->attr.nr_pages);
goto out_kill_hwq;
}
@@ -178,13 +178,13 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
if ((hret != H_SUCCESS) || (vpage)) {
ehea_error("registration of pages not "
- "complete hret=%lx\n", hret);
+ "complete hret=%llx\n", hret);
goto out_kill_hwq;
}
} else {
if (hret != H_PAGE_REGISTERED) {
ehea_error("CQ: registration of page failed "
- "hret=%lx\n", hret);
+ "hret=%llx\n", hret);
goto out_kill_hwq;
}
}
@@ -986,15 +986,15 @@ void print_error_data(u64 *data)
length = EHEA_PAGESIZE;
if (type == 0x8) /* Queue Pair */
- ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, "
- "port=%lX", resource, data[6], data[12], data[22]);
+ ehea_error("QP (resource=%llX) state: AER=0x%llX, AERR=0x%llX, "
+ "port=%llX", resource, data[6], data[12], data[22]);
if (type == 0x4) /* Completion Queue */
- ehea_error("CQ (resource=%lX) state: AER=0x%lX", resource,
+ ehea_error("CQ (resource=%llX) state: AER=0x%llX", resource,
data[6]);
if (type == 0x3) /* Event Queue */
- ehea_error("EQ (resource=%lX) state: AER=0x%lX", resource,
+ ehea_error("EQ (resource=%llX) state: AER=0x%llX", resource,
data[6]);
ehea_dump(data, length, "error data");
@@ -1016,11 +1016,11 @@ void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle)
rblock);
if (ret == H_R_STATE)
- ehea_error("No error data is available: %lX.", res_handle);
+ ehea_error("No error data is available: %llX.", res_handle);
else if (ret == H_SUCCESS)
print_error_data(rblock);
else
- ehea_error("Error data could not be fetched: %lX", res_handle);
+ ehea_error("Error data could not be fetched: %llX", res_handle);
kfree(rblock);
}
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index cefe1d98f93e..fc6cc038c7b8 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -1531,6 +1531,17 @@ static int enc28j60_chipset_init(struct net_device *dev)
return enc28j60_hw_init(priv);
}
+static const struct net_device_ops enc28j60_netdev_ops = {
+ .ndo_open = enc28j60_net_open,
+ .ndo_stop = enc28j60_net_close,
+ .ndo_start_xmit = enc28j60_send_packet,
+ .ndo_set_multicast_list = enc28j60_set_multicast_list,
+ .ndo_set_mac_address = enc28j60_set_mac_address,
+ .ndo_tx_timeout = enc28j60_tx_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
static int __devinit enc28j60_probe(struct spi_device *spi)
{
struct net_device *dev;
@@ -1585,12 +1596,7 @@ static int __devinit enc28j60_probe(struct spi_device *spi)
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->netdev_ops = &enc28j60_netdev_ops;
dev->watchdog_timeo = TX_TIMEOUT;
SET_ETHTOOL_OPS(dev, &enc28j60_ethtool_ops);
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index d039e16f2763..7d60551d538f 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -1599,6 +1599,7 @@ static const struct net_device_ops enic_netdev_ops = {
.ndo_start_xmit = enic_hard_start_xmit,
.ndo_get_stats = enic_get_stats,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_set_multicast_list = enic_set_multicast_list,
.ndo_change_mtu = enic_change_mtu,
.ndo_vlan_rx_register = enic_vlan_rx_register,
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index f9b37c80dda6..a539bc3163cf 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -308,7 +308,18 @@ static int epic_close(struct net_device *dev);
static struct net_device_stats *epic_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
-
+static const struct net_device_ops epic_netdev_ops = {
+ .ndo_open = epic_open,
+ .ndo_stop = epic_close,
+ .ndo_start_xmit = epic_start_xmit,
+ .ndo_tx_timeout = epic_tx_timeout,
+ .ndo_get_stats = epic_get_stats,
+ .ndo_set_multicast_list = set_rx_mode,
+ .ndo_do_ioctl = netdev_ioctl,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
static int __devinit epic_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -483,15 +494,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
dev->if_port = ep->default_port = option;
/* The Epic-specific entries in the device structure. */
- dev->open = &epic_open;
- dev->hard_start_xmit = &epic_start_xmit;
- dev->stop = &epic_close;
- dev->get_stats = &epic_get_stats;
- dev->set_multicast_list = &set_rx_mode;
- dev->do_ioctl = &netdev_ioctl;
+ dev->netdev_ops = &epic_netdev_ops;
dev->ethtool_ops = &netdev_ethtool_ops;
dev->watchdog_timeo = TX_TIMEOUT;
- dev->tx_timeout = &epic_tx_timeout;
netif_napi_add(dev, &ep->napi, epic_poll, 64);
ret = register_netdev(dev);
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index 31ab1ff623fc..daf7272c3352 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -467,6 +467,18 @@ static void stop_nic_rxtx(void __iomem *ioaddr, long crvalue)
}
}
+static const struct net_device_ops netdev_ops = {
+ .ndo_open = netdev_open,
+ .ndo_stop = netdev_close,
+ .ndo_start_xmit = start_tx,
+ .ndo_get_stats = get_stats,
+ .ndo_set_multicast_list = set_rx_mode,
+ .ndo_do_ioctl = mii_ioctl,
+ .ndo_tx_timeout = fealnx_tx_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
static int __devinit fealnx_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -649,15 +661,8 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
np->mii.force_media = 1;
}
- /* The chip-specific entries in the device structure. */
- dev->open = &netdev_open;
- dev->hard_start_xmit = &start_tx;
- dev->stop = &netdev_close;
- dev->get_stats = &get_stats;
- dev->set_multicast_list = &set_rx_mode;
- dev->do_ioctl = &mii_ioctl;
+ dev->netdev_ops = &netdev_ops;
dev->ethtool_ops = &netdev_ethtool_ops;
- dev->tx_timeout = &fealnx_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
err = register_netdev(dev);
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 5b68dc20168d..5b910cf63740 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -13,7 +13,7 @@
* Copyright (C) 2004 Andrew de Quincey (wol support)
* Copyright (C) 2004 Carl-Daniel Hailfinger (invalid MAC handling, insane
* IRQ rate fixes, bigendian fixes, cleanups, verification)
- * Copyright (c) 2004,2005,2006,2007,2008 NVIDIA Corporation
+ * Copyright (c) 2004,2005,2006,2007,2008,2009 NVIDIA 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
@@ -39,7 +39,7 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
-#define FORCEDETH_VERSION "0.61"
+#define FORCEDETH_VERSION "0.62"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -2096,14 +2096,15 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
}
+ spin_lock_irqsave(&np->lock, flags);
empty_slots = nv_get_empty_tx_slots(np);
if (unlikely(empty_slots <= entries)) {
- spin_lock_irqsave(&np->lock, flags);
netif_stop_queue(dev);
np->tx_stop = 1;
spin_unlock_irqrestore(&np->lock, flags);
return NETDEV_TX_BUSY;
}
+ spin_unlock_irqrestore(&np->lock, flags);
start_tx = put_tx = np->put_tx.orig;
@@ -2214,14 +2215,15 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev)
((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
}
+ spin_lock_irqsave(&np->lock, flags);
empty_slots = nv_get_empty_tx_slots(np);
if (unlikely(empty_slots <= entries)) {
- spin_lock_irqsave(&np->lock, flags);
netif_stop_queue(dev);
np->tx_stop = 1;
spin_unlock_irqrestore(&np->lock, flags);
return NETDEV_TX_BUSY;
}
+ spin_unlock_irqrestore(&np->lock, flags);
start_tx = put_tx = np->put_tx.ex;
start_tx_ctx = np->put_tx_ctx;
@@ -3403,10 +3405,10 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
#ifdef CONFIG_FORCEDETH_NAPI
if (events & NVREG_IRQ_RX_ALL) {
+ spin_lock(&np->lock);
netif_rx_schedule(&np->napi);
/* Disable furthur receive irq's */
- spin_lock(&np->lock);
np->irqmask &= ~NVREG_IRQ_RX_ALL;
if (np->msi_flags & NV_MSI_X_ENABLED)
@@ -3520,10 +3522,10 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
#ifdef CONFIG_FORCEDETH_NAPI
if (events & NVREG_IRQ_RX_ALL) {
+ spin_lock(&np->lock);
netif_rx_schedule(&np->napi);
/* Disable furthur receive irq's */
- spin_lock(&np->lock);
np->irqmask &= ~NVREG_IRQ_RX_ALL;
if (np->msi_flags & NV_MSI_X_ENABLED)
@@ -6167,19 +6169,19 @@ static struct pci_device_id pci_tbl[] = {
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36),
- .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+ .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{ /* MCP79 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
},
{0,},
};
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 4e6a9195fe5f..ce900e54d8d1 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -795,6 +795,7 @@ static int fs_enet_open(struct net_device *dev)
err = fs_init_phy(dev);
if (err) {
+ free_irq(fep->interrupt, dev);
if (fep->fpi->use_napi)
napi_disable(&fep->napi);
return err;
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index c672ecfc9595..ea530673236e 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -238,8 +238,8 @@ static int gfar_of_init(struct net_device *dev)
goto err_out;
}
- snprintf(priv->phy_bus_id, BUS_ID_SIZE, PHY_ID_FMT, "0",
- fixed_link[0]);
+ snprintf(priv->phy_bus_id, sizeof(priv->phy_bus_id),
+ PHY_ID_FMT, "0", fixed_link[0]);
} else {
phy = of_find_node_by_phandle(*ph);
@@ -256,7 +256,7 @@ static int gfar_of_init(struct net_device *dev)
of_node_put(mdio);
gfar_mdio_bus_name(bus_name, mdio);
- snprintf(priv->phy_bus_id, BUS_ID_SIZE, "%s:%02x",
+ snprintf(priv->phy_bus_id, sizeof(priv->phy_bus_id), "%s:%02x",
bus_name, *id);
}
@@ -296,6 +296,20 @@ err_out:
return err;
}
+/* Ioctl MII Interface */
+static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ if (!priv->phydev)
+ return -ENODEV;
+
+ return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
+}
+
/* Set up the ethernet device structure, private data,
* and anything else we need before we start */
static int gfar_probe(struct of_device *ofdev,
@@ -366,6 +380,7 @@ static int gfar_probe(struct of_device *ofdev,
dev->set_multicast_list = gfar_set_multi;
dev->ethtool_ops = &gfar_ethtool_ops;
+ dev->do_ioctl = gfar_ioctl;
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
priv->rx_csum_enable = 1;
@@ -1607,10 +1622,18 @@ static int gfar_clean_tx_ring(struct net_device *dev)
static void gfar_schedule_cleanup(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->txlock, flags);
+ spin_lock(&priv->rxlock);
+
if (netif_rx_schedule_prep(&priv->napi)) {
gfar_write(&priv->regs->imask, IMASK_RTX_DISABLED);
__netif_rx_schedule(&priv->napi);
}
+
+ spin_unlock(&priv->rxlock);
+ spin_unlock_irqrestore(&priv->txlock, flags);
}
/* Interrupt Handler for Transmit complete */
@@ -1973,6 +1996,8 @@ static void adjust_link(struct net_device *dev)
case 1000:
tempval =
((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII);
+
+ ecntrl &= ~(ECNTRL_R100);
break;
case 100:
case 10:
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 32200227c923..7e8b3c59a7d6 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -576,6 +576,7 @@ static const struct net_device_ops hamachi_netdev_ops = {
.ndo_set_multicast_list = set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_tx_timeout = hamachi_tx_timeout,
.ndo_do_ioctl = netdev_ioctl,
};
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 50f1e172ee8f..2d4089894ec7 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -717,11 +717,12 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct sixpack *sp = sp_get(tty);
- struct net_device *dev = sp->dev;
+ struct net_device *dev;
unsigned int tmp, err;
if (!sp)
return -ENXIO;
+ dev = sp->dev;
switch(cmd) {
case SIOCGIFNAME:
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index b507dbc16e62..5e070f446635 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -166,6 +166,7 @@ static const struct net_device_ops hpp_netdev_ops = {
.ndo_get_stats = eip_get_stats,
.ndo_set_multicast_list = eip_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = eip_poll,
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index ebe7651fcb86..ad8be7e78290 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -425,6 +425,28 @@ struct net_device * __init hp100_probe(int unit)
}
#endif /* !MODULE && CONFIG_ISA */
+static const struct net_device_ops hp100_bm_netdev_ops = {
+ .ndo_open = hp100_open,
+ .ndo_stop = hp100_close,
+ .ndo_start_xmit = hp100_start_xmit_bm,
+ .ndo_get_stats = hp100_get_stats,
+ .ndo_set_multicast_list = hp100_set_multicast_list,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+static const struct net_device_ops hp100_netdev_ops = {
+ .ndo_open = hp100_open,
+ .ndo_stop = hp100_close,
+ .ndo_start_xmit = hp100_start_xmit,
+ .ndo_get_stats = hp100_get_stats,
+ .ndo_set_multicast_list = hp100_set_multicast_list,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
u_char bus, struct pci_dev *pci_dev)
{
@@ -657,16 +679,10 @@ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
lp->virt_memory_size = virt_memory_size;
lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */
- dev->open = hp100_open;
- dev->stop = hp100_close;
-
if (lp->mode == 1) /* busmaster */
- dev->hard_start_xmit = hp100_start_xmit_bm;
+ dev->netdev_ops = &hp100_bm_netdev_ops;
else
- dev->hard_start_xmit = hp100_start_xmit;
-
- dev->get_stats = hp100_get_stats;
- dev->set_multicast_list = &hp100_set_multicast_list;
+ dev->netdev_ops = &hp100_netdev_ops;
/* Ask the card for which IRQ line it is configured */
if (bus == HP100_BUS_PCI) {
diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c
index 9cb38a8d4387..8ac0930c183c 100644
--- a/drivers/net/hydra.c
+++ b/drivers/net/hydra.c
@@ -103,6 +103,7 @@ static const struct net_device_ops hydra_netdev_ops = {
.ndo_get_stats = ei_get_stats,
.ndo_set_multicast_list = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ei_poll,
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c
index ecf9798987fa..2a2fc17b2878 100644
--- a/drivers/net/ibm_newemac/mal.c
+++ b/drivers/net/ibm_newemac/mal.c
@@ -613,7 +613,9 @@ static int __devinit mal_probe(struct of_device *ofdev,
INIT_LIST_HEAD(&mal->list);
spin_lock_init(&mal->lock);
- netif_napi_add(NULL, &mal->napi, mal_poll,
+ init_dummy_netdev(&mal->dummy_dev);
+
+ netif_napi_add(&mal->dummy_dev, &mal->napi, mal_poll,
CONFIG_IBM_NEW_EMAC_POLL_WEIGHT);
/* Load power-on reset defaults */
diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h
index 2f0a87360844..9ededfbf0726 100644
--- a/drivers/net/ibm_newemac/mal.h
+++ b/drivers/net/ibm_newemac/mal.h
@@ -214,6 +214,8 @@ struct mal_instance {
int index;
spinlock_t lock;
+ struct net_device dummy_dev;
+
unsigned int features;
};
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 9bc0f178f24b..dfa6348ac1dc 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -602,7 +602,7 @@ static int ibmveth_open(struct net_device *netdev)
if(lpar_rc != H_SUCCESS) {
ibmveth_error_printk("h_register_logical_lan failed with %ld\n", lpar_rc);
- ibmveth_error_printk("buffer TCE:0x%lx filter TCE:0x%lx rxq desc:0x%lx MAC:0x%lx\n",
+ ibmveth_error_printk("buffer TCE:0x%llx filter TCE:0x%llx rxq desc:0x%llx MAC:0x%llx\n",
adapter->buffer_list_dma,
adapter->filter_list_dma,
rxq_desc.desc,
@@ -754,7 +754,7 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
void (*done) (struct net_device *, u32))
{
struct ibmveth_adapter *adapter = netdev_priv(dev);
- u64 set_attr, clr_attr, ret_attr;
+ unsigned long set_attr, clr_attr, ret_attr;
long ret;
int rc1 = 0, rc2 = 0;
int restart = 0;
@@ -1209,7 +1209,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
long ret;
struct net_device *netdev;
struct ibmveth_adapter *adapter;
- u64 set_attr, ret_attr;
+ unsigned long set_attr, ret_attr;
unsigned char *mac_addr_p;
unsigned int *mcastFilterSize_p;
@@ -1378,13 +1378,13 @@ static int ibmveth_show(struct seq_file *seq, void *v)
seq_printf(seq, "Firmware MAC: %pM\n", firmware_mac);
seq_printf(seq, "\nAdapter Statistics:\n");
- seq_printf(seq, " TX: vio_map_single failres: %ld\n", adapter->tx_map_failed);
- seq_printf(seq, " send failures: %ld\n", adapter->tx_send_failed);
- seq_printf(seq, " RX: replenish task cycles: %ld\n", adapter->replenish_task_cycles);
- seq_printf(seq, " alloc_skb_failures: %ld\n", adapter->replenish_no_mem);
- seq_printf(seq, " add buffer failures: %ld\n", adapter->replenish_add_buff_failure);
- seq_printf(seq, " invalid buffers: %ld\n", adapter->rx_invalid_buffer);
- seq_printf(seq, " no buffers: %ld\n", adapter->rx_no_buffer);
+ seq_printf(seq, " TX: vio_map_single failres: %lld\n", adapter->tx_map_failed);
+ seq_printf(seq, " send failures: %lld\n", adapter->tx_send_failed);
+ seq_printf(seq, " RX: replenish task cycles: %lld\n", adapter->replenish_task_cycles);
+ seq_printf(seq, " alloc_skb_failures: %lld\n", adapter->replenish_no_mem);
+ seq_printf(seq, " add buffer failures: %lld\n", adapter->replenish_add_buff_failure);
+ seq_printf(seq, " invalid buffers: %lld\n", adapter->rx_invalid_buffer);
+ seq_printf(seq, " no buffers: %lld\n", adapter->rx_no_buffer);
return 0;
}
diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h
index d28186948752..ec76ace66c6b 100644
--- a/drivers/net/ibmveth.h
+++ b/drivers/net/ibmveth.h
@@ -39,11 +39,11 @@
#define IbmVethMcastRemoveFilter 0x2UL
#define IbmVethMcastClearFilterTable 0x3UL
-#define IBMVETH_ILLAN_PADDED_PKT_CSUM 0x0000000000002000ULL
-#define IBMVETH_ILLAN_TRUNK_PRI_MASK 0x0000000000000F00ULL
-#define IBMVETH_ILLAN_IPV6_TCP_CSUM 0x0000000000000004ULL
-#define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002ULL
-#define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001ULL
+#define IBMVETH_ILLAN_PADDED_PKT_CSUM 0x0000000000002000UL
+#define IBMVETH_ILLAN_TRUNK_PRI_MASK 0x0000000000000F00UL
+#define IBMVETH_ILLAN_IPV6_TCP_CSUM 0x0000000000000004UL
+#define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002UL
+#define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001UL
/* hcall macros */
#define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
index 7b6d435a8468..360aa5e35fda 100644
--- a/drivers/net/ipg.c
+++ b/drivers/net/ipg.c
@@ -2210,6 +2210,19 @@ static void __devexit ipg_remove(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
}
+static const struct net_device_ops ipg_netdev_ops = {
+ .ndo_open = ipg_nic_open,
+ .ndo_stop = ipg_nic_stop,
+ .ndo_start_xmit = ipg_nic_hard_start_xmit,
+ .ndo_get_stats = ipg_nic_get_stats,
+ .ndo_set_multicast_list = ipg_nic_set_multicast_list,
+ .ndo_do_ioctl = ipg_ioctl,
+ .ndo_tx_timeout = ipg_tx_timeout,
+ .ndo_change_mtu = ipg_nic_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
static int __devinit ipg_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -2258,15 +2271,7 @@ static int __devinit ipg_probe(struct pci_dev *pdev,
/* Declare IPG NIC functions for Ethernet device methods.
*/
- dev->open = &ipg_nic_open;
- dev->stop = &ipg_nic_stop;
- dev->hard_start_xmit = &ipg_nic_hard_start_xmit;
- dev->get_stats = &ipg_nic_get_stats;
- dev->set_multicast_list = &ipg_nic_set_multicast_list;
- dev->do_ioctl = ipg_ioctl;
- dev->tx_timeout = ipg_tx_timeout;
- dev->change_mtu = &ipg_nic_change_mtu;
-
+ dev->netdev_ops = &ipg_netdev_ops;
SET_NETDEV_DEV(dev, &pdev->dev);
SET_ETHTOOL_OPS(dev, &ipg_ethtool_ops);
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index 3c58e67ef1e4..17779f9bffc4 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -109,7 +109,6 @@ static int ali_ircc_net_open(struct net_device *dev);
static int ali_ircc_net_close(struct net_device *dev);
static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud);
-static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev);
/* SIR function */
static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -366,7 +365,6 @@ static int ali_ircc_open(int i, chipio_t *info)
dev->open = ali_ircc_net_open;
dev->stop = ali_ircc_net_close;
dev->do_ioctl = ali_ircc_net_ioctl;
- dev->get_stats = ali_ircc_net_get_stats;
err = register_netdev(dev);
if (err) {
@@ -876,7 +874,7 @@ static void ali_ircc_sir_receive(struct ali_ircc_cb *self)
* async_unwrap_char will deliver all found frames
*/
do {
- async_unwrap_char(self->netdev, &self->stats, &self->rx_buff,
+ async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff,
inb(iobase+UART_RX));
/* Make sure we don't stay here too long */
@@ -943,7 +941,7 @@ static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self)
netif_wake_queue(self->netdev);
}
- self->stats.tx_packets++;
+ self->netdev->stats.tx_packets++;
/* Turn on receive interrupts */
outb(UART_IER_RDI, iobase+UART_IER);
@@ -1467,7 +1465,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
self->tx_fifo.tail += skb->len;
- self->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start,
skb->len);
@@ -1661,12 +1659,12 @@ static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self)
{
IRDA_ERROR("%s(), ********* LSR_FRAME_ABORT *********\n", __func__);
- self->stats.tx_errors++;
- self->stats.tx_fifo_errors++;
+ self->netdev->stats.tx_errors++;
+ self->netdev->stats.tx_fifo_errors++;
}
else
{
- self->stats.tx_packets++;
+ self->netdev->stats.tx_packets++;
}
/* Check if we need to change the speed */
@@ -1831,35 +1829,35 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self)
IRDA_DEBUG(0,"%s(), ************* RX Errors ************ \n", __func__ );
/* Skip frame */
- self->stats.rx_errors++;
+ self->netdev->stats.rx_errors++;
self->rx_buff.data += len;
if (status & LSR_FIFO_UR)
{
- self->stats.rx_frame_errors++;
+ self->netdev->stats.rx_frame_errors++;
IRDA_DEBUG(0,"%s(), ************* FIFO Errors ************ \n", __func__ );
}
if (status & LSR_FRAME_ERROR)
{
- self->stats.rx_frame_errors++;
+ self->netdev->stats.rx_frame_errors++;
IRDA_DEBUG(0,"%s(), ************* FRAME Errors ************ \n", __func__ );
}
if (status & LSR_CRC_ERROR)
{
- self->stats.rx_crc_errors++;
+ self->netdev->stats.rx_crc_errors++;
IRDA_DEBUG(0,"%s(), ************* CRC Errors ************ \n", __func__ );
}
if(self->rcvFramesOverflow)
{
- self->stats.rx_frame_errors++;
+ self->netdev->stats.rx_frame_errors++;
IRDA_DEBUG(0,"%s(), ************* Overran DMA buffer ************ \n", __func__ );
}
if(len == 0)
{
- self->stats.rx_frame_errors++;
+ self->netdev->stats.rx_frame_errors++;
IRDA_DEBUG(0,"%s(), ********** Receive Frame Size = 0 ********* \n", __func__ );
}
}
@@ -1910,7 +1908,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self)
IRDA_WARNING("%s(), memory squeeze, "
"dropping frame.\n",
__func__);
- self->stats.rx_dropped++;
+ self->netdev->stats.rx_dropped++;
return FALSE;
}
@@ -1924,8 +1922,8 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self)
/* Move to next frame */
self->rx_buff.data += len;
- self->stats.rx_bytes += len;
- self->stats.rx_packets++;
+ self->netdev->stats.rx_bytes += len;
+ self->netdev->stats.rx_packets++;
skb->dev = self->netdev;
skb_reset_mac_header(skb);
@@ -1994,7 +1992,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
self->tx_buff.truesize);
- self->stats.tx_bytes += self->tx_buff.len;
+ self->netdev->stats.tx_bytes += self->tx_buff.len;
/* Turn on transmit finished interrupt. Will fire immediately! */
outb(UART_IER_THRI, iobase+UART_IER);
@@ -2111,17 +2109,6 @@ static int ali_ircc_is_receiving(struct ali_ircc_cb *self)
return status;
}
-static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev)
-{
- struct ali_ircc_cb *self = netdev_priv(dev);
-
- IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ );
-
- IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
-
- return &self->stats;
-}
-
static int ali_ircc_suspend(struct platform_device *dev, pm_message_t state)
{
struct ali_ircc_cb *self = platform_get_drvdata(dev);
diff --git a/drivers/net/irda/ali-ircc.h b/drivers/net/irda/ali-ircc.h
index ed35d99763d5..0c8edb41bd0a 100644
--- a/drivers/net/irda/ali-ircc.h
+++ b/drivers/net/irda/ali-ircc.h
@@ -191,7 +191,6 @@ struct ali_ircc_cb {
struct tx_fifo tx_fifo; /* Info about frames to be transmitted */
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 binded to */
struct qos_info qos; /* QoS capabilities for this device */
diff --git a/drivers/net/irda/au1000_ircc.h b/drivers/net/irda/au1000_ircc.h
index b4763f24dded..c072c09a8d91 100644
--- a/drivers/net/irda/au1000_ircc.h
+++ b/drivers/net/irda/au1000_ircc.h
@@ -107,7 +107,6 @@ struct au1k_private {
iobuff_t rx_buff;
struct net_device *netdev;
- struct net_device_stats stats;
struct timeval stamp;
struct timeval now;
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index 6c4b53ffbcac..941164076a2b 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -53,7 +53,6 @@ static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *);
static int au1k_irda_rx(struct net_device *);
static void au1k_irda_interrupt(int, void *);
static void au1k_tx_timeout(struct net_device *);
-static struct net_device_stats *au1k_irda_stats(struct net_device *);
static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int);
static int au1k_irda_set_speed(struct net_device *dev, int speed);
@@ -213,7 +212,6 @@ static int au1k_irda_net_init(struct net_device *dev)
dev->open = au1k_irda_start;
dev->hard_start_xmit = au1k_irda_hard_xmit;
dev->stop = au1k_irda_stop;
- dev->get_stats = au1k_irda_stats;
dev->do_ioctl = au1k_irda_ioctl;
dev->tx_timeout = au1k_tx_timeout;
@@ -596,7 +594,7 @@ static int au1k_irda_rx(struct net_device *dev)
update_rx_stats(dev, flags, count);
skb=alloc_skb(count+1,GFP_ATOMIC);
if (skb == NULL) {
- aup->stats.rx_dropped++;
+ aup->netdev->stats.rx_dropped++;
continue;
}
skb_reserve(skb, 1);
@@ -832,13 +830,6 @@ au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
return ret;
}
-
-static struct net_device_stats *au1k_irda_stats(struct net_device *dev)
-{
- struct au1k_private *aup = netdev_priv(dev);
- return &aup->stats;
-}
-
MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>");
MODULE_DESCRIPTION("Au1000 IrDA Device Driver");
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 687c2d53d4d2..6f3e7f71658d 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -1194,13 +1194,13 @@ toshoboe_interrupt (int irq, void *dev_id)
txp = txpc;
txpc++;
txpc %= TX_SLOTS;
- self->stats.tx_packets++;
+ self->netdev->stats.tx_packets++;
if (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS)
self->ring->tx[txp].control &= ~OBOE_CTL_TX_RTCENTX;
}
- self->stats.tx_packets--;
+ self->netdev->stats.tx_packets--;
#else
- self->stats.tx_packets++;
+ self->netdev->stats.tx_packets++;
#endif
toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX);
}
@@ -1280,7 +1280,7 @@ dumpbufs(self->rx_bufs[self->rxs],len,'<');
skb_put (skb, len);
skb_copy_to_linear_data(skb, self->rx_bufs[self->rxs],
len);
- self->stats.rx_packets++;
+ self->netdev->stats.rx_packets++;
skb->dev = self->netdev;
skb_reset_mac_header(skb);
skb->protocol = htons (ETH_P_IRDA);
diff --git a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h
index 1e67720f1066..0dbd1932b72f 100644
--- a/drivers/net/irda/donauboe.h
+++ b/drivers/net/irda/donauboe.h
@@ -308,7 +308,6 @@ struct OboeRing
struct toshoboe_cb
{
struct net_device *netdev; /* Yes! we are some kind of netdevice */
- struct net_device_stats stats;
struct tty_driver ttydev;
struct irlap_cb *irlap; /* The link layer we are binded to */
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 205e4e825a97..3a22dc41b656 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -122,7 +122,6 @@ static int irda_usb_net_open(struct net_device *dev);
static int irda_usb_net_close(struct net_device *dev);
static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void irda_usb_net_timeout(struct net_device *dev);
-static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev);
/************************ TRANSMIT ROUTINES ************************/
/*
@@ -525,13 +524,13 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
/* Ask USB to send the packet - Irq disabled -> GFP_ATOMIC */
if ((res = usb_submit_urb(urb, GFP_ATOMIC))) {
IRDA_WARNING("%s(), failed Tx URB\n", __func__);
- self->stats.tx_errors++;
+ netdev->stats.tx_errors++;
/* Let USB recover : We will catch that in the watchdog */
/*netif_start_queue(netdev);*/
} else {
/* Increment packet stats */
- self->stats.tx_packets++;
- self->stats.tx_bytes += skb->len;
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += skb->len;
netdev->trans_start = jiffies;
}
@@ -677,7 +676,7 @@ static void irda_usb_net_timeout(struct net_device *netdev)
IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags);
/* Increase error count */
- self->stats.tx_errors++;
+ netdev->stats.tx_errors++;
#ifdef IU_BUG_KICK_TIMEOUT
/* Can't be a bad idea to reset the speed ;-) - Jean II */
@@ -826,7 +825,7 @@ static void irda_usb_receive(struct urb *urb)
if (urb->status != 0) {
switch (urb->status) {
case -EILSEQ:
- self->stats.rx_crc_errors++;
+ self->netdev->stats.rx_crc_errors++;
/* Also precursor to a hot-unplug on UHCI. */
/* Fallthrough... */
case -ECONNRESET:
@@ -839,7 +838,7 @@ static void irda_usb_receive(struct urb *urb)
case -ETIME:
/* Usually precursor to a hot-unplug on OHCI. */
default:
- self->stats.rx_errors++;
+ self->netdev->stats.rx_errors++;
IRDA_DEBUG(0, "%s(), RX status %d, transfer_flags 0x%04X \n", __func__, urb->status, urb->transfer_flags);
break;
}
@@ -890,7 +889,7 @@ static void irda_usb_receive(struct urb *urb)
IRDA_SKB_MAX_MTU);
if (!newskb) {
- self->stats.rx_dropped++;
+ self->netdev->stats.rx_dropped++;
/* We could deliver the current skb, but this would stall
* the Rx path. Better drop the packet... Jean II */
goto done;
@@ -927,8 +926,8 @@ static void irda_usb_receive(struct urb *urb)
netif_rx(dataskb);
/* Keep stats up to date */
- self->stats.rx_bytes += len;
- self->stats.rx_packets++;
+ self->netdev->stats.rx_bytes += len;
+ self->netdev->stats.rx_packets++;
done:
/* Note : at this point, the URB we've just received (urb)
@@ -1074,7 +1073,7 @@ static int stir421x_patch_device(struct irda_usb_cb *self)
{
unsigned int i;
int ret;
- char stir421x_fw_name[11];
+ char stir421x_fw_name[12];
const struct firmware *fw;
const unsigned char *fw_version_ptr; /* pointer to version string */
unsigned long fw_version = 0;
@@ -1342,14 +1341,6 @@ static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
/*------------------------------------------------------------------*/
-/*
- * Get device stats (for /proc/net/dev and ifconfig)
- */
-static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev)
-{
- struct irda_usb_cb *self = netdev_priv(dev);
- return &self->stats;
-}
/********************* IRDA CONFIG SUBROUTINES *********************/
/*
@@ -1428,7 +1419,6 @@ static inline int irda_usb_open(struct irda_usb_cb *self)
netdev->watchdog_timeo = 250*HZ/1000; /* 250 ms > USB timeout */
netdev->open = irda_usb_net_open;
netdev->stop = irda_usb_net_close;
- netdev->get_stats = irda_usb_net_get_stats;
netdev->do_ioctl = irda_usb_net_ioctl;
return register_netdev(netdev);
diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h
index a0ca9c1fe196..ac0443d52e50 100644
--- a/drivers/net/irda/irda-usb.h
+++ b/drivers/net/irda/irda-usb.h
@@ -152,7 +152,6 @@ struct irda_usb_cb {
struct urb *speed_urb; /* URB used to send speed commands */
struct net_device *netdev; /* Yes! we are some kind of netdev. */
- struct net_device_stats stats;
struct irlap_cb *irlap; /* The link layer we are binded to */
struct qos_info qos;
char *speed_buff; /* Buffer for speed changes */
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
index c747c874d44d..b4a61717254a 100644
--- a/drivers/net/irda/kingsun-sir.c
+++ b/drivers/net/irda/kingsun-sir.c
@@ -105,7 +105,7 @@ struct kingsun_cb {
struct usb_device *usbdev; /* init: probe_irda */
struct net_device *netdev; /* network layer */
struct irlap_cb *irlap; /* The link layer we are binded to */
- struct net_device_stats stats; /* network statistics */
+
struct qos_info qos;
__u8 *in_buf; /* receive buffer */
@@ -186,12 +186,12 @@ static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
case -EPIPE:
break;
default:
- kingsun->stats.tx_errors++;
+ netdev->stats.tx_errors++;
netif_start_queue(netdev);
}
} else {
- kingsun->stats.tx_packets++;
- kingsun->stats.tx_bytes += skb->len;
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += skb->len;
}
dev_kfree_skb(skb);
@@ -232,7 +232,7 @@ static void kingsun_rcv_irq(struct urb *urb)
if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) {
for (i = 1; i <= bytes[0]; i++) {
async_unwrap_char(kingsun->netdev,
- &kingsun->stats,
+ &kingsun->netdev->stats,
&kingsun->rx_buff, bytes[i]);
}
do_gettimeofday(&kingsun->rx_time);
@@ -418,15 +418,6 @@ static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq,
return ret;
}
-/*
- * Get device stats (for /proc/net/dev and ifconfig)
- */
-static struct net_device_stats *
-kingsun_net_get_stats(struct net_device *netdev)
-{
- struct kingsun_cb *kingsun = netdev_priv(netdev);
- return &kingsun->stats;
-}
/*
* This routine is called by the USB subsystem for each new device
@@ -532,7 +523,6 @@ static int kingsun_probe(struct usb_interface *intf,
net->hard_start_xmit = kingsun_hard_xmit;
net->open = kingsun_net_open;
net->stop = kingsun_net_close;
- net->get_stats = kingsun_net_get_stats;
net->do_ioctl = kingsun_net_ioctl;
ret = register_netdev(net);
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
index 600d96f9cdb7..55322fb92cf1 100644
--- a/drivers/net/irda/ks959-sir.c
+++ b/drivers/net/irda/ks959-sir.c
@@ -174,7 +174,7 @@ struct ks959_cb {
struct usb_device *usbdev; /* init: probe_irda */
struct net_device *netdev; /* network layer */
struct irlap_cb *irlap; /* The link layer we are binded to */
- struct net_device_stats stats; /* network statistics */
+
struct qos_info qos;
struct usb_ctrlrequest *tx_setuprequest;
@@ -366,7 +366,7 @@ static void ks959_send_irq(struct urb *urb)
case -EPIPE:
break;
default:
- kingsun->stats.tx_errors++;
+ netdev->stats.tx_errors++;
netif_start_queue(netdev);
}
}
@@ -416,12 +416,12 @@ static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
case -EPIPE:
break;
default:
- kingsun->stats.tx_errors++;
+ netdev->stats.tx_errors++;
netif_start_queue(netdev);
}
} else {
- kingsun->stats.tx_packets++;
- kingsun->stats.tx_bytes += skb->len;
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += skb->len;
}
@@ -469,7 +469,7 @@ static void ks959_rcv_irq(struct urb *urb)
*/
if (kingsun->rx_variable_xormask != 0) {
async_unwrap_char(kingsun->netdev,
- &kingsun->stats,
+ &kingsun->netdev->stats,
&kingsun->rx_unwrap_buff,
bytes[i]);
}
@@ -669,15 +669,6 @@ static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
}
/*
- * Get device stats (for /proc/net/dev and ifconfig)
- */
-static struct net_device_stats *ks959_net_get_stats(struct net_device *netdev)
-{
- struct ks959_cb *kingsun = netdev_priv(netdev);
- return &kingsun->stats;
-}
-
-/*
* This routine is called by the USB subsystem for each new device
* in the system. We need to check if the device is ours, and in
* this case start handling it.
@@ -792,7 +783,6 @@ static int ks959_probe(struct usb_interface *intf,
net->hard_start_xmit = ks959_hard_xmit;
net->open = ks959_net_open;
net->stop = ks959_net_close;
- net->get_stats = ks959_net_get_stats;
net->do_ioctl = ks959_net_ioctl;
ret = register_netdev(net);
diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c
index 0e7f89337b25..5b327b09acd8 100644
--- a/drivers/net/irda/ksdazzle-sir.c
+++ b/drivers/net/irda/ksdazzle-sir.c
@@ -140,7 +140,7 @@ struct ksdazzle_cb {
struct usb_device *usbdev; /* init: probe_irda */
struct net_device *netdev; /* network layer */
struct irlap_cb *irlap; /* The link layer we are binded to */
- struct net_device_stats stats; /* network statistics */
+
struct qos_info qos;
struct urb *tx_urb;
@@ -278,7 +278,7 @@ static void ksdazzle_send_irq(struct urb *urb)
case -EPIPE:
break;
default:
- kingsun->stats.tx_errors++;
+ netdev->stats.tx_errors++;
netif_start_queue(netdev);
}
}
@@ -329,12 +329,12 @@ static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
case -EPIPE:
break;
default:
- kingsun->stats.tx_errors++;
+ netdev->stats.tx_errors++;
netif_start_queue(netdev);
}
} else {
- kingsun->stats.tx_packets++;
- kingsun->stats.tx_bytes += skb->len;
+ netdev->stats.tx_packets++;
+ netdev->stats.tx_bytes += skb->len;
}
@@ -348,9 +348,10 @@ static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
static void ksdazzle_rcv_irq(struct urb *urb)
{
struct ksdazzle_cb *kingsun = urb->context;
+ struct net_device *netdev = kingsun->netdev;
/* in process of stopping, just drop data */
- if (!netif_running(kingsun->netdev)) {
+ if (!netif_running(netdev)) {
kingsun->receiving = 0;
return;
}
@@ -368,7 +369,7 @@ static void ksdazzle_rcv_irq(struct urb *urb)
unsigned int i;
for (i = 0; i < urb->actual_length; i++) {
- async_unwrap_char(kingsun->netdev, &kingsun->stats,
+ async_unwrap_char(netdev, &netdev->stats,
&kingsun->rx_unwrap_buff, bytes[i]);
}
kingsun->receiving =
@@ -562,16 +563,6 @@ static int ksdazzle_net_ioctl(struct net_device *netdev, struct ifreq *rq,
}
/*
- * Get device stats (for /proc/net/dev and ifconfig)
- */
-static struct net_device_stats *ksdazzle_net_get_stats(struct net_device
- *netdev)
-{
- struct ksdazzle_cb *kingsun = netdev_priv(netdev);
- return &kingsun->stats;
-}
-
-/*
* This routine is called by the USB subsystem for each new device
* in the system. We need to check if the device is ours, and in
* this case start handling it.
@@ -696,7 +687,6 @@ static int ksdazzle_probe(struct usb_interface *intf,
net->hard_start_xmit = ksdazzle_hard_xmit;
net->open = ksdazzle_net_open;
net->stop = ksdazzle_net_close;
- net->get_stats = ksdazzle_net_get_stats;
net->do_ioctl = ksdazzle_net_ioctl;
ret = register_netdev(net);
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index 904c9610c0dd..7eafdca19f34 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -403,8 +403,8 @@ static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len)
if(unlikely(new_len <= 0)) {
IRDA_ERROR("%s short frame length %d\n",
mcs->netdev->name, new_len);
- ++mcs->stats.rx_errors;
- ++mcs->stats.rx_length_errors;
+ ++mcs->netdev->stats.rx_errors;
+ ++mcs->netdev->stats.rx_length_errors;
return;
}
fcs = 0;
@@ -413,14 +413,14 @@ static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len)
if(fcs != GOOD_FCS) {
IRDA_ERROR("crc error calc 0x%x len %d\n",
fcs, new_len);
- mcs->stats.rx_errors++;
- mcs->stats.rx_crc_errors++;
+ mcs->netdev->stats.rx_errors++;
+ mcs->netdev->stats.rx_crc_errors++;
return;
}
skb = dev_alloc_skb(new_len + 1);
if(unlikely(!skb)) {
- ++mcs->stats.rx_dropped;
+ ++mcs->netdev->stats.rx_dropped;
return;
}
@@ -433,8 +433,8 @@ static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len)
netif_rx(skb);
- mcs->stats.rx_packets++;
- mcs->stats.rx_bytes += new_len;
+ mcs->netdev->stats.rx_packets++;
+ mcs->netdev->stats.rx_bytes += new_len;
return;
}
@@ -458,22 +458,22 @@ static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len)
if(unlikely(new_len <= 0)) {
IRDA_ERROR("%s short frame length %d\n",
mcs->netdev->name, new_len);
- ++mcs->stats.rx_errors;
- ++mcs->stats.rx_length_errors;
+ ++mcs->netdev->stats.rx_errors;
+ ++mcs->netdev->stats.rx_length_errors;
return;
}
fcs = ~(crc32_le(~0, buf, new_len));
if(fcs != get_unaligned_le32(buf + new_len)) {
IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len);
- mcs->stats.rx_errors++;
- mcs->stats.rx_crc_errors++;
+ mcs->netdev->stats.rx_errors++;
+ mcs->netdev->stats.rx_crc_errors++;
return;
}
skb = dev_alloc_skb(new_len + 1);
if(unlikely(!skb)) {
- ++mcs->stats.rx_dropped;
+ ++mcs->netdev->stats.rx_dropped;
return;
}
@@ -486,8 +486,8 @@ static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len)
netif_rx(skb);
- mcs->stats.rx_packets++;
- mcs->stats.rx_bytes += new_len;
+ mcs->netdev->stats.rx_packets++;
+ mcs->netdev->stats.rx_bytes += new_len;
return;
}
@@ -756,14 +756,6 @@ static int mcs_net_open(struct net_device *netdev)
return ret;
}
-
-/* Get device stats for /proc/net/dev and ifconfig */
-static struct net_device_stats *mcs_net_get_stats(struct net_device *netdev)
-{
- struct mcs_cb *mcs = netdev_priv(netdev);
- return &mcs->stats;
-}
-
/* Receive callback function. */
static void mcs_receive_irq(struct urb *urb)
{
@@ -786,14 +778,14 @@ static void mcs_receive_irq(struct urb *urb)
*/
/* SIR speed */
if(mcs->speed < 576000) {
- async_unwrap_char(mcs->netdev, &mcs->stats,
+ async_unwrap_char(mcs->netdev, &mcs->netdev->stats,
&mcs->rx_buff, 0xc0);
for (i = 0; i < urb->actual_length; i++)
- async_unwrap_char(mcs->netdev, &mcs->stats,
+ async_unwrap_char(mcs->netdev, &mcs->netdev->stats,
&mcs->rx_buff, bytes[i]);
- async_unwrap_char(mcs->netdev, &mcs->stats,
+ async_unwrap_char(mcs->netdev, &mcs->netdev->stats,
&mcs->rx_buff, 0xc1);
}
/* MIR speed */
@@ -868,12 +860,12 @@ static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
case -EPIPE:
break;
default:
- mcs->stats.tx_errors++;
+ mcs->netdev->stats.tx_errors++;
netif_start_queue(ndev);
}
} else {
- mcs->stats.tx_packets++;
- mcs->stats.tx_bytes += skb->len;
+ mcs->netdev->stats.tx_packets++;
+ mcs->netdev->stats.tx_bytes += skb->len;
}
dev_kfree_skb(skb);
@@ -931,7 +923,6 @@ static int mcs_probe(struct usb_interface *intf,
ndev->hard_start_xmit = mcs_hard_xmit;
ndev->open = mcs_net_open;
ndev->stop = mcs_net_close;
- ndev->get_stats = mcs_net_get_stats;
ndev->do_ioctl = mcs_net_ioctl;
if (!intf->cur_altsetting)
diff --git a/drivers/net/irda/mcs7780.h b/drivers/net/irda/mcs7780.h
index b18148cee638..6bdc621e67c6 100644
--- a/drivers/net/irda/mcs7780.h
+++ b/drivers/net/irda/mcs7780.h
@@ -104,7 +104,6 @@ struct mcs_cb {
struct usb_device *usbdev; /* init: probe_irda */
struct net_device *netdev; /* network layer */
struct irlap_cb *irlap; /* The link layer we are binded to */
- struct net_device_stats stats; /* network statistics */
struct qos_info qos;
unsigned int speed; /* Current speed */
unsigned int new_speed; /* new speed */
@@ -154,7 +153,6 @@ static int mcs_speed_change(struct mcs_cb *mcs);
static int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd);
static int mcs_net_close(struct net_device *netdev);
static int mcs_net_open(struct net_device *netdev);
-static struct net_device_stats *mcs_net_get_stats(struct net_device *netdev);
static void mcs_receive_irq(struct urb *urb);
static void mcs_send_irq(struct urb *urb);
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 2c6bf2d11bb1..61e509cb712a 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -185,7 +185,6 @@ static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id);
static int nsc_ircc_net_open(struct net_device *dev);
static int nsc_ircc_net_close(struct net_device *dev);
static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev);
/* Globals */
static int pnp_registered;
@@ -446,7 +445,6 @@ static int __init nsc_ircc_open(chipio_t *info)
dev->open = nsc_ircc_net_open;
dev->stop = nsc_ircc_net_close;
dev->do_ioctl = nsc_ircc_net_ioctl;
- dev->get_stats = nsc_ircc_net_get_stats;
err = register_netdev(dev);
if (err) {
@@ -1401,7 +1399,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
self->tx_buff.truesize);
- self->stats.tx_bytes += self->tx_buff.len;
+ dev->stats.tx_bytes += self->tx_buff.len;
/* Add interrupt on tx low level (will fire immediately) */
switch_bank(iobase, BANK0);
@@ -1473,7 +1471,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
self->tx_fifo.tail += skb->len;
- self->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start,
skb->len);
@@ -1652,13 +1650,13 @@ static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self)
/* Check for underrrun! */
if (inb(iobase+ASCR) & ASCR_TXUR) {
- self->stats.tx_errors++;
- self->stats.tx_fifo_errors++;
+ self->netdev->stats.tx_errors++;
+ self->netdev->stats.tx_fifo_errors++;
/* Clear bit, by writing 1 into it */
outb(ASCR_TXUR, iobase+ASCR);
} else {
- self->stats.tx_packets++;
+ self->netdev->stats.tx_packets++;
}
/* Finished with this frame, so prepare for next */
@@ -1793,28 +1791,28 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase)
if (status & FRM_ST_ERR_MSK) {
if (status & FRM_ST_LOST_FR) {
/* Add number of lost frames to stats */
- self->stats.rx_errors += len;
+ self->netdev->stats.rx_errors += len;
} else {
/* Skip frame */
- self->stats.rx_errors++;
+ self->netdev->stats.rx_errors++;
self->rx_buff.data += len;
if (status & FRM_ST_MAX_LEN)
- self->stats.rx_length_errors++;
+ self->netdev->stats.rx_length_errors++;
if (status & FRM_ST_PHY_ERR)
- self->stats.rx_frame_errors++;
+ self->netdev->stats.rx_frame_errors++;
if (status & FRM_ST_BAD_CRC)
- self->stats.rx_crc_errors++;
+ self->netdev->stats.rx_crc_errors++;
}
/* The errors below can be reported in both cases */
if (status & FRM_ST_OVR1)
- self->stats.rx_fifo_errors++;
+ self->netdev->stats.rx_fifo_errors++;
if (status & FRM_ST_OVR2)
- self->stats.rx_fifo_errors++;
+ self->netdev->stats.rx_fifo_errors++;
} else {
/*
* First we must make sure that the frame we
@@ -1863,7 +1861,7 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase)
IRDA_WARNING("%s(), memory squeeze, "
"dropping frame.\n",
__func__);
- self->stats.rx_dropped++;
+ self->netdev->stats.rx_dropped++;
/* Restore bank register */
outb(bank, iobase+BSR);
@@ -1889,8 +1887,8 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase)
/* Move to next frame */
self->rx_buff.data += len;
- self->stats.rx_bytes += len;
- self->stats.rx_packets++;
+ self->netdev->stats.rx_bytes += len;
+ self->netdev->stats.rx_packets++;
skb->dev = self->netdev;
skb_reset_mac_header(skb);
@@ -1920,8 +1918,8 @@ static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self)
/* Receive all characters in Rx FIFO */
do {
byte = inb(iobase+RXD);
- async_unwrap_char(self->netdev, &self->stats, &self->rx_buff,
- byte);
+ async_unwrap_char(self->netdev, &self->netdev->stats,
+ &self->rx_buff, byte);
} while (inb(iobase+LSR) & LSR_RXDA); /* Data available */
}
@@ -1952,7 +1950,7 @@ static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir)
self->ier = IER_TXLDL_IE;
else {
- self->stats.tx_packets++;
+ self->netdev->stats.tx_packets++;
netif_wake_queue(self->netdev);
self->ier = IER_TXEMP_IE;
}
@@ -2307,13 +2305,6 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return ret;
}
-static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev)
-{
- struct nsc_ircc_cb *self = netdev_priv(dev);
-
- return &self->stats;
-}
-
static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state)
{
struct nsc_ircc_cb *self = platform_get_drvdata(dev);
diff --git a/drivers/net/irda/nsc-ircc.h b/drivers/net/irda/nsc-ircc.h
index 71cd3c5a0762..7ba7738759b9 100644
--- a/drivers/net/irda/nsc-ircc.h
+++ b/drivers/net/irda/nsc-ircc.h
@@ -251,7 +251,6 @@ struct nsc_ircc_cb {
struct tx_fifo tx_fifo; /* Info about frames to be transmitted */
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 binded to */
struct qos_info qos; /* QoS capabilities for this device */
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index 004a9aab3a50..31794c2363ec 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -108,7 +108,6 @@ struct pxa_irda {
int txdma;
int rxdma;
- struct net_device_stats stats;
struct irlap_cb *irlap;
struct qos_info qos;
@@ -258,14 +257,15 @@ static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id)
data = STRBR;
if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) {
printk(KERN_DEBUG "pxa_ir: sir receiving error\n");
- si->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (lsr & LSR_FE)
- si->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (lsr & LSR_OE)
- si->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
} else {
- si->stats.rx_bytes++;
- async_unwrap_char(dev, &si->stats, &si->rx_buff, data);
+ dev->stats.rx_bytes++;
+ async_unwrap_char(dev, &dev->stats,
+ &si->rx_buff, data);
}
lsr = STLSR;
}
@@ -277,8 +277,8 @@ static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id)
case 0x0C: /* Character Timeout Indication */
do {
- si->stats.rx_bytes++;
- async_unwrap_char(dev, &si->stats, &si->rx_buff, STRBR);
+ dev->stats.rx_bytes++;
+ async_unwrap_char(dev, &dev->stats, &si->rx_buff, STRBR);
} while (STLSR & LSR_DR);
si->last_oscr = OSCR;
break;
@@ -290,9 +290,8 @@ static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id)
}
if (si->tx_buff.len == 0) {
- si->stats.tx_packets++;
- si->stats.tx_bytes += si->tx_buff.data -
- si->tx_buff.head;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head;
/* We need to ensure that the transmitter has finished. */
while ((STLSR & LSR_TEMT) == 0)
@@ -343,10 +342,10 @@ static void pxa_irda_fir_dma_tx_irq(int channel, void *data)
DCSR(channel) = dcsr & ~DCSR_RUN;
if (dcsr & DCSR_ENDINTR) {
- si->stats.tx_packets++;
- si->stats.tx_bytes += si->dma_tx_buff_len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += si->dma_tx_buff_len;
} else {
- si->stats.tx_errors++;
+ dev->stats.tx_errors++;
}
while (ICSR1 & ICSR1_TBY)
@@ -392,14 +391,14 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, in
data = ICDR;
if (stat & (ICSR1_CRE | ICSR1_ROR)) {
- si->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (stat & ICSR1_CRE) {
printk(KERN_DEBUG "pxa_ir: fir receive CRC error\n");
- si->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
}
if (stat & ICSR1_ROR) {
printk(KERN_DEBUG "pxa_ir: fir receive overrun\n");
- si->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
}
} else {
si->dma_rx_buff[len++] = data;
@@ -415,14 +414,14 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, in
if (icsr0 & ICSR0_FRE) {
printk(KERN_ERR "pxa_ir: dropping erroneous frame\n");
- si->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
skb = alloc_skb(len+1,GFP_ATOMIC);
if (!skb) {
printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n");
- si->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
return;
}
@@ -437,8 +436,8 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, in
skb->protocol = htons(ETH_P_IRDA);
netif_rx(skb);
- si->stats.rx_packets++;
- si->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
}
}
@@ -457,10 +456,10 @@ static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id)
if (icsr0 & (ICSR0_FRE | ICSR0_RAB)) {
if (icsr0 & ICSR0_FRE) {
printk(KERN_DEBUG "pxa_ir: fir receive frame error\n");
- si->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
} else {
printk(KERN_DEBUG "pxa_ir: fir receive abort\n");
- si->stats.rx_errors++;
+ dev->stats.rx_errors++;
}
ICSR0 = icsr0 & (ICSR0_FRE | ICSR0_RAB);
}
@@ -589,12 +588,6 @@ static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
return ret;
}
-static struct net_device_stats *pxa_irda_stats(struct net_device *dev)
-{
- struct pxa_irda *si = netdev_priv(dev);
- return &si->stats;
-}
-
static void pxa_irda_startup(struct pxa_irda *si)
{
/* Disable STUART interrupts */
@@ -857,7 +850,6 @@ static int pxa_irda_probe(struct platform_device *pdev)
dev->open = pxa_irda_start;
dev->stop = pxa_irda_stop;
dev->do_ioctl = pxa_irda_ioctl;
- dev->get_stats = pxa_irda_stats;
irda_init_max_qos_capabilies(&si->qos);
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index d302bcf4c148..7a2b003954ca 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -60,7 +60,6 @@ struct sa1100_irda {
dma_regs_t *txdma;
dma_regs_t *rxdma;
- struct net_device_stats stats;
struct device *dev;
struct irda_platform_data *pdata;
struct irlap_cb *irlap;
@@ -375,13 +374,13 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev)
data = Ser2UTDR;
if (stat & (UTSR1_FRE | UTSR1_ROR)) {
- si->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (stat & UTSR1_FRE)
- si->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (stat & UTSR1_ROR)
- si->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
} else
- async_unwrap_char(dev, &si->stats, &si->rx_buff, data);
+ async_unwrap_char(dev, &dev->stats, &si->rx_buff, data);
status = Ser2UTSR0;
}
@@ -396,9 +395,9 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev)
* There are at least 4 bytes in the FIFO. Read 3 bytes
* and leave the rest to the block below.
*/
- async_unwrap_char(dev, &si->stats, &si->rx_buff, Ser2UTDR);
- async_unwrap_char(dev, &si->stats, &si->rx_buff, Ser2UTDR);
- async_unwrap_char(dev, &si->stats, &si->rx_buff, Ser2UTDR);
+ async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
+ async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
+ async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR);
}
if (status & (UTSR0_RFS | UTSR0_RID)) {
@@ -406,7 +405,7 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev)
* Fifo contains more than 1 character.
*/
do {
- async_unwrap_char(dev, &si->stats, &si->rx_buff,
+ async_unwrap_char(dev, &dev->stats, &si->rx_buff,
Ser2UTDR);
} while (Ser2UTSR1 & UTSR1_RNE);
@@ -422,8 +421,8 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev)
} while (Ser2UTSR1 & UTSR1_TNF && si->tx_buff.len);
if (si->tx_buff.len == 0) {
- si->stats.tx_packets++;
- si->stats.tx_bytes += si->tx_buff.data -
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += si->tx_buff.data -
si->tx_buff.head;
/*
@@ -482,11 +481,11 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
data = Ser2HSDR;
if (stat & (HSSR1_CRE | HSSR1_ROR)) {
- si->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (stat & HSSR1_CRE)
- si->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (stat & HSSR1_ROR)
- si->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
} else
skb->data[len++] = data;
@@ -505,8 +504,8 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
skb->dev = dev;
skb_reset_mac_header(skb);
skb->protocol = htons(ETH_P_IRDA);
- si->stats.rx_packets++;
- si->stats.rx_bytes += len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
/*
* Before we pass the buffer up, allocate a new one.
@@ -545,10 +544,10 @@ static void sa1100_irda_fir_irq(struct net_device *dev)
* from the fifo.
*/
if (Ser2HSSR0 & (HSSR0_FRE | HSSR0_RAB)) {
- si->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (Ser2HSSR0 & HSSR0_FRE)
- si->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
/*
* Clear out the DMA...
@@ -633,8 +632,8 @@ static void sa1100_irda_txdma_irq(void *id)
*/
if (skb) {
dma_unmap_single(si->dev, si->txbuf_dma, skb->len, DMA_TO_DEVICE);
- si->stats.tx_packets ++;
- si->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets ++;
+ dev->stats.tx_bytes += skb->len;
dev_kfree_skb_irq(skb);
}
@@ -762,12 +761,6 @@ sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
return ret;
}
-static struct net_device_stats *sa1100_irda_stats(struct net_device *dev)
-{
- struct sa1100_irda *si = netdev_priv(dev);
- return &si->stats;
-}
-
static int sa1100_irda_start(struct net_device *dev)
{
struct sa1100_irda *si = netdev_priv(dev);
@@ -924,7 +917,6 @@ static int sa1100_irda_probe(struct platform_device *pdev)
dev->open = sa1100_irda_start;
dev->stop = sa1100_irda_stop;
dev->do_ioctl = sa1100_irda_ioctl;
- dev->get_stats = sa1100_irda_stats;
dev->irq = IRQ_Ser2ICP;
irda_init_max_qos_capabilies(&si->qos);
diff --git a/drivers/net/irda/sir-dev.h b/drivers/net/irda/sir-dev.h
index 2a57bc67ce35..6d5b1e2b1289 100644
--- a/drivers/net/irda/sir-dev.h
+++ b/drivers/net/irda/sir-dev.h
@@ -160,7 +160,6 @@ static inline int sirdev_schedule_mode(struct sir_dev *dev, int mode)
struct sir_dev {
struct net_device *netdev;
- struct net_device_stats stats;
struct irlap_cb *irlap;
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
index ceef040aa76d..5b5862499def 100644
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -455,8 +455,8 @@ void sirdev_write_complete(struct sir_dev *dev)
if ((skb=dev->tx_skb) != NULL) {
dev->tx_skb = NULL;
dev_kfree_skb_any(skb);
- dev->stats.tx_errors++;
- dev->stats.tx_dropped++;
+ dev->netdev->stats.tx_errors++;
+ dev->netdev->stats.tx_dropped++;
}
dev->tx_buff.len = 0;
}
@@ -493,8 +493,8 @@ void sirdev_write_complete(struct sir_dev *dev)
if ((skb=dev->tx_skb) != NULL) {
dev->tx_skb = NULL;
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
+ dev->netdev->stats.tx_packets++;
+ dev->netdev->stats.tx_bytes += skb->len;
dev_kfree_skb_any(skb);
}
@@ -548,7 +548,7 @@ int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count)
* just update stats and set media busy
*/
irda_device_set_media_busy(dev->netdev, TRUE);
- dev->stats.rx_dropped++;
+ dev->netdev->stats.rx_dropped++;
IRDA_DEBUG(0, "%s; rx-drop: %zd\n", __func__, count);
return 0;
}
@@ -557,7 +557,7 @@ int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count)
if (likely(atomic_read(&dev->enable_rx))) {
while (count--)
/* Unwrap and destuff one byte */
- async_unwrap_char(dev->netdev, &dev->stats,
+ async_unwrap_char(dev->netdev, &dev->netdev->stats,
&dev->rx_buff, *cp++);
} else {
while (count--) {
@@ -582,13 +582,6 @@ EXPORT_SYMBOL(sirdev_receive);
/* callbacks from network layer */
-static struct net_device_stats *sirdev_get_stats(struct net_device *ndev)
-{
- struct sir_dev *dev = netdev_priv(ndev);
-
- return (dev) ? &dev->stats : NULL;
-}
-
static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct sir_dev *dev = netdev_priv(ndev);
@@ -654,7 +647,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
*/
atomic_set(&dev->enable_rx, 0);
if (unlikely(sirdev_is_receiving(dev)))
- dev->stats.collisions++;
+ dev->netdev->stats.collisions++;
actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len);
@@ -669,8 +662,8 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
IRDA_ERROR("%s: drv->do_write failed (%d)\n",
__func__, actual);
dev_kfree_skb_any(skb);
- dev->stats.tx_errors++;
- dev->stats.tx_dropped++;
+ dev->netdev->stats.tx_errors++;
+ dev->netdev->stats.tx_dropped++;
netif_wake_queue(ndev);
}
spin_unlock_irqrestore(&dev->tx_lock, flags);
@@ -918,7 +911,6 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n
ndev->hard_start_xmit = sirdev_hard_xmit;
ndev->open = sirdev_open;
ndev->stop = sirdev_close;
- ndev->get_stats = sirdev_get_stats;
ndev->do_ioctl = sirdev_ioctl;
if (register_netdev(ndev)) {
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 5d09e157e15b..dd73cce10991 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -150,7 +150,6 @@ struct smsc_chip_address {
/* Private data for each instance */
struct smsc_ircc_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 binded to */
chipio_t io; /* IrDA controller information */
@@ -215,7 +214,6 @@ static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cm
#if SMSC_IRCC2_C_NET_TIMEOUT
static void smsc_ircc_timeout(struct net_device *dev);
#endif
-static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev);
static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self);
static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self);
static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed);
@@ -529,7 +527,6 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
dev->open = smsc_ircc_net_open;
dev->stop = smsc_ircc_net_close;
dev->do_ioctl = smsc_ircc_net_ioctl;
- dev->get_stats = smsc_ircc_net_get_stats;
self = netdev_priv(dev);
self->netdev = dev;
@@ -834,13 +831,6 @@ static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd
return ret;
}
-static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev)
-{
- struct smsc_ircc_cb *self = netdev_priv(dev);
-
- return &self->stats;
-}
-
#if SMSC_IRCC2_C_NET_TIMEOUT
/*
* Function smsc_ircc_timeout (struct net_device *dev)
@@ -920,7 +910,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data,
self->tx_buff.truesize);
- self->stats.tx_bytes += self->tx_buff.len;
+ dev->stats.tx_bytes += self->tx_buff.len;
/* Turn on transmit finished interrupt. Will fire immediately! */
outb(UART_IER_THRI, self->io.sir_base + UART_IER);
@@ -1320,16 +1310,16 @@ static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self)
/* Check for underrun! */
register_bank(iobase, 0);
if (inb(iobase + IRCC_LSR) & IRCC_LSR_UNDERRUN) {
- self->stats.tx_errors++;
- self->stats.tx_fifo_errors++;
+ self->netdev->stats.tx_errors++;
+ self->netdev->stats.tx_fifo_errors++;
/* Reset error condition */
register_bank(iobase, 0);
outb(IRCC_MASTER_ERROR_RESET, iobase + IRCC_MASTER);
outb(0x00, iobase + IRCC_MASTER);
} else {
- self->stats.tx_packets++;
- self->stats.tx_bytes += self->tx_buff.len;
+ self->netdev->stats.tx_packets++;
+ self->netdev->stats.tx_bytes += self->tx_buff.len;
}
/* Check if it's time to change the speed */
@@ -1429,15 +1419,15 @@ static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self)
/* Look for errors */
if (lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) {
- self->stats.rx_errors++;
+ self->netdev->stats.rx_errors++;
if (lsr & IRCC_LSR_FRAME_ERROR)
- self->stats.rx_frame_errors++;
+ self->netdev->stats.rx_frame_errors++;
if (lsr & IRCC_LSR_CRC_ERROR)
- self->stats.rx_crc_errors++;
+ self->netdev->stats.rx_crc_errors++;
if (lsr & IRCC_LSR_SIZE_ERROR)
- self->stats.rx_length_errors++;
+ self->netdev->stats.rx_length_errors++;
if (lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN))
- self->stats.rx_length_errors++;
+ self->netdev->stats.rx_length_errors++;
return;
}
@@ -1460,8 +1450,8 @@ static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self)
skb_reserve(skb, 1);
memcpy(skb_put(skb, len), self->rx_buff.data, len);
- self->stats.rx_packets++;
- self->stats.rx_bytes += len;
+ self->netdev->stats.rx_packets++;
+ self->netdev->stats.rx_bytes += len;
skb->dev = self->netdev;
skb_reset_mac_header(skb);
@@ -1489,7 +1479,7 @@ static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self)
* async_unwrap_char will deliver all found frames
*/
do {
- async_unwrap_char(self->netdev, &self->stats, &self->rx_buff,
+ async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff,
inb(iobase + UART_RX));
/* Make sure we don't stay here to long */
@@ -1992,7 +1982,7 @@ static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self)
/* Tell network layer that we want more frames */
netif_wake_queue(self->netdev);
}
- self->stats.tx_packets++;
+ self->netdev->stats.tx_packets++;
if (self->io.speed <= 115200) {
/*
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index ca4cd9266e55..8b1658c6c925 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -164,7 +164,7 @@ struct stir_cb {
struct usb_device *usbdev; /* init: probe_irda */
struct net_device *netdev; /* network layer */
struct irlap_cb *irlap; /* The link layer we are binded to */
- struct net_device_stats stats; /* network statistics */
+
struct qos_info qos;
unsigned speed; /* Current speed */
@@ -323,16 +323,16 @@ static void fir_eof(struct stir_cb *stir)
pr_debug("%s: short frame len %d\n",
stir->netdev->name, len);
- ++stir->stats.rx_errors;
- ++stir->stats.rx_length_errors;
+ ++stir->netdev->stats.rx_errors;
+ ++stir->netdev->stats.rx_length_errors;
return;
}
fcs = ~(crc32_le(~0, rx_buff->data, len));
if (fcs != get_unaligned_le32(rx_buff->data + len)) {
pr_debug("crc error calc 0x%x len %d\n", fcs, len);
- stir->stats.rx_errors++;
- stir->stats.rx_crc_errors++;
+ stir->netdev->stats.rx_errors++;
+ stir->netdev->stats.rx_crc_errors++;
return;
}
@@ -340,7 +340,7 @@ static void fir_eof(struct stir_cb *stir)
if (len < IRDA_RX_COPY_THRESHOLD) {
nskb = dev_alloc_skb(len + 1);
if (unlikely(!nskb)) {
- ++stir->stats.rx_dropped;
+ ++stir->netdev->stats.rx_dropped;
return;
}
skb_reserve(nskb, 1);
@@ -349,7 +349,7 @@ static void fir_eof(struct stir_cb *stir)
} else {
nskb = dev_alloc_skb(rx_buff->truesize);
if (unlikely(!nskb)) {
- ++stir->stats.rx_dropped;
+ ++stir->netdev->stats.rx_dropped;
return;
}
skb_reserve(nskb, 1);
@@ -366,8 +366,8 @@ static void fir_eof(struct stir_cb *stir)
netif_rx(skb);
- stir->stats.rx_packets++;
- stir->stats.rx_bytes += len;
+ stir->netdev->stats.rx_packets++;
+ stir->netdev->stats.rx_bytes += len;
rx_buff->data = rx_buff->head;
rx_buff->len = 0;
@@ -437,7 +437,7 @@ static void stir_fir_chars(struct stir_cb *stir,
if (unlikely(rx_buff->len >= rx_buff->truesize)) {
pr_debug("%s: fir frame exceeds %d\n",
stir->netdev->name, rx_buff->truesize);
- ++stir->stats.rx_over_errors;
+ ++stir->netdev->stats.rx_over_errors;
goto error_recovery;
}
@@ -445,10 +445,10 @@ static void stir_fir_chars(struct stir_cb *stir,
continue;
frame_error:
- ++stir->stats.rx_frame_errors;
+ ++stir->netdev->stats.rx_frame_errors;
error_recovery:
- ++stir->stats.rx_errors;
+ ++stir->netdev->stats.rx_errors;
rx_buff->state = OUTSIDE_FRAME;
rx_buff->in_frame = FALSE;
}
@@ -461,7 +461,7 @@ static void stir_sir_chars(struct stir_cb *stir,
int i;
for (i = 0; i < len; i++)
- async_unwrap_char(stir->netdev, &stir->stats,
+ async_unwrap_char(stir->netdev, &stir->netdev->stats,
&stir->rx_buff, bytes[i]);
}
@@ -692,7 +692,7 @@ static void receive_stop(struct stir_cb *stir)
usb_kill_urb(stir->rx_urb);
if (stir->rx_buff.in_frame)
- stir->stats.collisions++;
+ stir->netdev->stats.collisions++;
}
/*
* Wrap data in socket buffer and send it.
@@ -718,15 +718,15 @@ static void stir_send(struct stir_cb *stir, struct sk_buff *skb)
if (!first_frame)
fifo_txwait(stir, wraplen);
- stir->stats.tx_packets++;
- stir->stats.tx_bytes += skb->len;
+ stir->netdev->stats.tx_packets++;
+ stir->netdev->stats.tx_bytes += skb->len;
stir->netdev->trans_start = jiffies;
pr_debug("send %d (%d)\n", skb->len, wraplen);
if (usb_bulk_msg(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1),
stir->io_buf, wraplen,
NULL, TRANSMIT_TIMEOUT))
- stir->stats.tx_errors++;
+ stir->netdev->stats.tx_errors++;
}
/*
@@ -1008,15 +1008,6 @@ static int stir_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
}
/*
- * Get device stats (for /proc/net/dev and ifconfig)
- */
-static struct net_device_stats *stir_net_get_stats(struct net_device *netdev)
-{
- struct stir_cb *stir = netdev_priv(netdev);
- return &stir->stats;
-}
-
-/*
* This routine is called by the USB subsystem for each new device
* in the system. We need to check if the device is ours, and in
* this case start handling it.
@@ -1066,7 +1057,6 @@ static int stir_probe(struct usb_interface *intf,
net->hard_start_xmit = stir_hard_xmit;
net->open = stir_net_open;
net->stop = stir_net_close;
- net->get_stats = stir_net_get_stats;
net->do_ioctl = stir_net_ioctl;
ret = register_netdev(net);
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index 74c78cf7a333..8b3e545924cc 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -101,8 +101,6 @@ static int via_ircc_net_open(struct net_device *dev);
static int via_ircc_net_close(struct net_device *dev);
static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq,
int cmd);
-static struct net_device_stats *via_ircc_net_get_stats(struct net_device
- *dev);
static void via_ircc_change_dongle_speed(int iobase, int speed,
int dongle_id);
static int RxTimerHandler(struct via_ircc_cb *self, int iobase);
@@ -434,7 +432,6 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id)
dev->open = via_ircc_net_open;
dev->stop = via_ircc_net_close;
dev->do_ioctl = via_ircc_net_ioctl;
- dev->get_stats = via_ircc_net_get_stats;
err = register_netdev(dev);
if (err)
@@ -855,7 +852,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb,
async_wrap_skb(skb, self->tx_buff.data,
self->tx_buff.truesize);
- self->stats.tx_bytes += self->tx_buff.len;
+ dev->stats.tx_bytes += self->tx_buff.len;
/* Send this frame with old speed */
SetBaudRate(iobase, self->io.speed);
SetPulseWidth(iobase, 12);
@@ -921,7 +918,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
self->tx_fifo.tail += skb->len;
- self->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
skb_copy_from_linear_data(skb,
self->tx_fifo.queue[self->tx_fifo.free].start, skb->len);
self->tx_fifo.len++;
@@ -990,12 +987,12 @@ static int via_ircc_dma_xmit_complete(struct via_ircc_cb *self)
/* Clear bit, by writing 1 into it */
Tx_status = GetTXStatus(iobase);
if (Tx_status & 0x08) {
- self->stats.tx_errors++;
- self->stats.tx_fifo_errors++;
+ self->netdev->stats.tx_errors++;
+ self->netdev->stats.tx_fifo_errors++;
hwreset(self);
// how to clear underrrun ?
} else {
- self->stats.tx_packets++;
+ self->netdev->stats.tx_packets++;
ResetChip(iobase, 3);
ResetChip(iobase, 4);
}
@@ -1119,8 +1116,8 @@ static int via_ircc_dma_receive_complete(struct via_ircc_cb *self,
}
// Move to next frame
self->rx_buff.data += len;
- self->stats.rx_bytes += len;
- self->stats.rx_packets++;
+ self->netdev->stats.rx_bytes += len;
+ self->netdev->stats.rx_packets++;
skb->dev = self->netdev;
skb_reset_mac_header(skb);
skb->protocol = htons(ETH_P_IRDA);
@@ -1180,7 +1177,7 @@ F01_E */
*/
if ((skb == NULL) || (skb->data == NULL)
|| (self->rx_buff.data == NULL) || (len < 6)) {
- self->stats.rx_dropped++;
+ self->netdev->stats.rx_dropped++;
return TRUE;
}
skb_reserve(skb, 1);
@@ -1192,8 +1189,8 @@ F01_E */
// Move to next frame
self->rx_buff.data += len;
- self->stats.rx_bytes += len;
- self->stats.rx_packets++;
+ self->netdev->stats.rx_bytes += len;
+ self->netdev->stats.rx_packets++;
skb->dev = self->netdev;
skb_reset_mac_header(skb);
skb->protocol = htons(ETH_P_IRDA);
@@ -1220,13 +1217,13 @@ static int upload_rxdata(struct via_ircc_cb *self, int iobase)
IRDA_DEBUG(2, "%s(): len=%x\n", __func__, len);
if ((len - 4) < 2) {
- self->stats.rx_dropped++;
+ self->netdev->stats.rx_dropped++;
return FALSE;
}
skb = dev_alloc_skb(len + 1);
if (skb == NULL) {
- self->stats.rx_dropped++;
+ self->netdev->stats.rx_dropped++;
return FALSE;
}
skb_reserve(skb, 1);
@@ -1238,8 +1235,8 @@ static int upload_rxdata(struct via_ircc_cb *self, int iobase)
st_fifo->tail = 0;
// Move to next frame
self->rx_buff.data += len;
- self->stats.rx_bytes += len;
- self->stats.rx_packets++;
+ self->netdev->stats.rx_bytes += len;
+ self->netdev->stats.rx_packets++;
skb->dev = self->netdev;
skb_reset_mac_header(skb);
skb->protocol = htons(ETH_P_IRDA);
@@ -1295,7 +1292,7 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase)
*/
if ((skb == NULL) || (skb->data == NULL)
|| (self->rx_buff.data == NULL) || (len < 6)) {
- self->stats.rx_dropped++;
+ self->netdev->stats.rx_dropped++;
continue;
}
skb_reserve(skb, 1);
@@ -1307,8 +1304,8 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase)
// Move to next frame
self->rx_buff.data += len;
- self->stats.rx_bytes += len;
- self->stats.rx_packets++;
+ self->netdev->stats.rx_bytes += len;
+ self->netdev->stats.rx_packets++;
skb->dev = self->netdev;
skb_reset_mac_header(skb);
skb->protocol = htons(ETH_P_IRDA);
@@ -1523,7 +1520,7 @@ static int via_ircc_net_open(struct net_device *dev)
IRDA_ASSERT(dev != NULL, return -1;);
self = netdev_priv(dev);
- self->stats.rx_packets = 0;
+ dev->stats.rx_packets = 0;
IRDA_ASSERT(self != NULL, return 0;);
iobase = self->io.fir_base;
if (request_irq(self->io.irq, via_ircc_interrupt, 0, dev->name, dev)) {
@@ -1660,14 +1657,6 @@ static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq,
return ret;
}
-static struct net_device_stats *via_ircc_net_get_stats(struct net_device
- *dev)
-{
- struct via_ircc_cb *self = netdev_priv(dev);
-
- return &self->stats;
-}
-
MODULE_AUTHOR("VIA Technologies,inc");
MODULE_DESCRIPTION("VIA IrDA Device Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/via-ircc.h b/drivers/net/irda/via-ircc.h
index 403c3f77634c..d9d1db03fa2d 100644
--- a/drivers/net/irda/via-ircc.h
+++ b/drivers/net/irda/via-ircc.h
@@ -95,7 +95,6 @@ struct via_ircc_cb {
struct tx_fifo tx_fifo; /* Info about frames to be transmitted */
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 binded to */
struct qos_info qos; /* QoS capabilities for this device */
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index 0d30f8d659a1..723c4588c803 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -291,14 +291,14 @@ static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev)
now.tv_sec - idev->last_rx.tv_sec - delta1, delta2);
seq_printf(seq, "RX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu",
- idev->stats.rx_packets, idev->stats.rx_bytes, idev->stats.rx_errors,
- idev->stats.rx_dropped);
+ ndev->stats.rx_packets, ndev->stats.rx_bytes, ndev->stats.rx_errors,
+ ndev->stats.rx_dropped);
seq_printf(seq, " / overrun=%lu / length=%lu / frame=%lu / crc=%lu\n",
- idev->stats.rx_over_errors, idev->stats.rx_length_errors,
- idev->stats.rx_frame_errors, idev->stats.rx_crc_errors);
+ ndev->stats.rx_over_errors, ndev->stats.rx_length_errors,
+ ndev->stats.rx_frame_errors, ndev->stats.rx_crc_errors);
seq_printf(seq, "TX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu / fifo=%lu\n",
- idev->stats.tx_packets, idev->stats.tx_bytes, idev->stats.tx_errors,
- idev->stats.tx_dropped, idev->stats.tx_fifo_errors);
+ ndev->stats.tx_packets, ndev->stats.tx_bytes, ndev->stats.tx_errors,
+ ndev->stats.tx_dropped, ndev->stats.tx_fifo_errors);
}
@@ -651,21 +651,21 @@ static void vlsi_rx_interrupt(struct net_device *ndev)
if (ret < 0) {
ret = -ret;
- idev->stats.rx_errors++;
+ ndev->stats.rx_errors++;
if (ret & VLSI_RX_DROP)
- idev->stats.rx_dropped++;
+ ndev->stats.rx_dropped++;
if (ret & VLSI_RX_OVER)
- idev->stats.rx_over_errors++;
+ ndev->stats.rx_over_errors++;
if (ret & VLSI_RX_LENGTH)
- idev->stats.rx_length_errors++;
+ ndev->stats.rx_length_errors++;
if (ret & VLSI_RX_FRAME)
- idev->stats.rx_frame_errors++;
+ ndev->stats.rx_frame_errors++;
if (ret & VLSI_RX_CRC)
- idev->stats.rx_crc_errors++;
+ ndev->stats.rx_crc_errors++;
}
else if (ret > 0) {
- idev->stats.rx_packets++;
- idev->stats.rx_bytes += ret;
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += ret;
}
}
@@ -686,6 +686,7 @@ static void vlsi_rx_interrupt(struct net_device *ndev)
static void vlsi_unarm_rx(vlsi_irda_dev_t *idev)
{
+ struct net_device *ndev = pci_get_drvdata(idev->pdev);
struct vlsi_ring *r = idev->rx_ring;
struct ring_descr *rd;
int ret;
@@ -711,21 +712,21 @@ static void vlsi_unarm_rx(vlsi_irda_dev_t *idev)
if (ret < 0) {
ret = -ret;
- idev->stats.rx_errors++;
+ ndev->stats.rx_errors++;
if (ret & VLSI_RX_DROP)
- idev->stats.rx_dropped++;
+ ndev->stats.rx_dropped++;
if (ret & VLSI_RX_OVER)
- idev->stats.rx_over_errors++;
+ ndev->stats.rx_over_errors++;
if (ret & VLSI_RX_LENGTH)
- idev->stats.rx_length_errors++;
+ ndev->stats.rx_length_errors++;
if (ret & VLSI_RX_FRAME)
- idev->stats.rx_frame_errors++;
+ ndev->stats.rx_frame_errors++;
if (ret & VLSI_RX_CRC)
- idev->stats.rx_crc_errors++;
+ ndev->stats.rx_crc_errors++;
}
else if (ret > 0) {
- idev->stats.rx_packets++;
- idev->stats.rx_bytes += ret;
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += ret;
}
}
}
@@ -1050,8 +1051,8 @@ drop_unlock:
drop:
IRDA_WARNING("%s: dropping packet - %s\n", __func__, msg);
dev_kfree_skb_any(skb);
- idev->stats.tx_errors++;
- idev->stats.tx_dropped++;
+ ndev->stats.tx_errors++;
+ ndev->stats.tx_dropped++;
/* Don't even think about returning NET_XMIT_DROP (=1) here!
* In fact any retval!=0 causes the packet scheduler to requeue the
* packet for later retry of transmission - which isn't exactly
@@ -1078,15 +1079,15 @@ static void vlsi_tx_interrupt(struct net_device *ndev)
if (ret < 0) {
ret = -ret;
- idev->stats.tx_errors++;
+ ndev->stats.tx_errors++;
if (ret & VLSI_TX_DROP)
- idev->stats.tx_dropped++;
+ ndev->stats.tx_dropped++;
if (ret & VLSI_TX_FIFO)
- idev->stats.tx_fifo_errors++;
+ ndev->stats.tx_fifo_errors++;
}
else if (ret > 0){
- idev->stats.tx_packets++;
- idev->stats.tx_bytes += ret;
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += ret;
}
}
@@ -1122,6 +1123,7 @@ static void vlsi_tx_interrupt(struct net_device *ndev)
static void vlsi_unarm_tx(vlsi_irda_dev_t *idev)
{
+ struct net_device *ndev = pci_get_drvdata(idev->pdev);
struct vlsi_ring *r = idev->tx_ring;
struct ring_descr *rd;
int ret;
@@ -1145,15 +1147,15 @@ static void vlsi_unarm_tx(vlsi_irda_dev_t *idev)
if (ret < 0) {
ret = -ret;
- idev->stats.tx_errors++;
+ ndev->stats.tx_errors++;
if (ret & VLSI_TX_DROP)
- idev->stats.tx_dropped++;
+ ndev->stats.tx_dropped++;
if (ret & VLSI_TX_FIFO)
- idev->stats.tx_fifo_errors++;
+ ndev->stats.tx_fifo_errors++;
}
else if (ret > 0){
- idev->stats.tx_packets++;
- idev->stats.tx_bytes += ret;
+ ndev->stats.tx_packets++;
+ ndev->stats.tx_bytes += ret;
}
}
@@ -1373,13 +1375,6 @@ static int vlsi_stop_hw(vlsi_irda_dev_t *idev)
/**************************************************************/
-static struct net_device_stats * vlsi_get_stats(struct net_device *ndev)
-{
- vlsi_irda_dev_t *idev = netdev_priv(ndev);
-
- return &idev->stats;
-}
-
static void vlsi_tx_timeout(struct net_device *ndev)
{
vlsi_irda_dev_t *idev = netdev_priv(ndev);
@@ -1615,7 +1610,6 @@ static int vlsi_irda_init(struct net_device *ndev)
ndev->open = vlsi_open;
ndev->stop = vlsi_close;
- ndev->get_stats = vlsi_get_stats;
ndev->hard_start_xmit = vlsi_hard_start_xmit;
ndev->do_ioctl = vlsi_ioctl;
ndev->tx_timeout = vlsi_tx_timeout;
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
index 9b1884329fba..3050d1a0cccf 100644
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -712,7 +712,6 @@ static inline struct ring_descr *ring_get(struct vlsi_ring *r)
typedef struct vlsi_irda_dev {
struct pci_dev *pdev;
- struct net_device_stats stats;
struct irlap_cb *irlap;
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 30ec9131c5ce..dc0a2e4d830f 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -102,7 +102,6 @@ static int w83977af_is_receiving(struct w83977af_ir *self);
static int w83977af_net_open(struct net_device *dev);
static int w83977af_net_close(struct net_device *dev);
static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *w83977af_net_get_stats(struct net_device *dev);
/*
* Function w83977af_init ()
@@ -237,7 +236,6 @@ static int w83977af_open(int i, unsigned int iobase, unsigned int irq,
dev->open = w83977af_net_open;
dev->stop = w83977af_net_close;
dev->do_ioctl = w83977af_net_ioctl;
- dev->get_stats = w83977af_net_get_stats;
err = register_netdev(dev);
if (err) {
@@ -702,13 +700,13 @@ static void w83977af_dma_xmit_complete(struct w83977af_ir *self)
if (inb(iobase+AUDR) & AUDR_UNDR) {
IRDA_DEBUG(0, "%s(), Transmit underrun!\n", __func__ );
- self->stats.tx_errors++;
- self->stats.tx_fifo_errors++;
+ self->netdev->stats.tx_errors++;
+ self->netdev->stats.tx_fifo_errors++;
/* Clear bit, by writing 1 to it */
outb(AUDR_UNDR, iobase+AUDR);
} else
- self->stats.tx_packets++;
+ self->netdev->stats.tx_packets++;
if (self->new_speed) {
@@ -846,28 +844,28 @@ static int w83977af_dma_receive_complete(struct w83977af_ir *self)
if (status & FS_FO_ERR_MSK) {
if (status & FS_FO_LST_FR) {
/* Add number of lost frames to stats */
- self->stats.rx_errors += len;
+ self->netdev->stats.rx_errors += len;
} else {
/* Skip frame */
- self->stats.rx_errors++;
+ self->netdev->stats.rx_errors++;
self->rx_buff.data += len;
if (status & FS_FO_MX_LEX)
- self->stats.rx_length_errors++;
+ self->netdev->stats.rx_length_errors++;
if (status & FS_FO_PHY_ERR)
- self->stats.rx_frame_errors++;
+ self->netdev->stats.rx_frame_errors++;
if (status & FS_FO_CRC_ERR)
- self->stats.rx_crc_errors++;
+ self->netdev->stats.rx_crc_errors++;
}
/* The errors below can be reported in both cases */
if (status & FS_FO_RX_OV)
- self->stats.rx_fifo_errors++;
+ self->netdev->stats.rx_fifo_errors++;
if (status & FS_FO_FSF_OV)
- self->stats.rx_fifo_errors++;
+ self->netdev->stats.rx_fifo_errors++;
} else {
/* Check if we have transferred all data to memory */
@@ -917,7 +915,7 @@ static int w83977af_dma_receive_complete(struct w83977af_ir *self)
/* Move to next frame */
self->rx_buff.data += len;
- self->stats.rx_packets++;
+ self->netdev->stats.rx_packets++;
skb->dev = self->netdev;
skb_reset_mac_header(skb);
@@ -951,7 +949,7 @@ static void w83977af_pio_receive(struct w83977af_ir *self)
/* Receive all characters in Rx FIFO */
do {
byte = inb(iobase+RBR);
- async_unwrap_char(self->netdev, &self->stats, &self->rx_buff,
+ async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff,
byte);
} while (inb(iobase+USR) & USR_RDR); /* Data available */
}
@@ -994,7 +992,7 @@ static __u8 w83977af_sir_interrupt(struct w83977af_ir *self, int isr)
outb(AUDR_SFEND, iobase+AUDR);
outb(set, iobase+SSR);
- self->stats.tx_packets++;
+ self->netdev->stats.tx_packets++;
/* Feed me more packets */
netif_wake_queue(self->netdev);
@@ -1336,13 +1334,6 @@ out:
return ret;
}
-static struct net_device_stats *w83977af_net_get_stats(struct net_device *dev)
-{
- struct w83977af_ir *self = netdev_priv(dev);
-
- return &self->stats;
-}
-
MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
MODULE_DESCRIPTION("Winbond W83977AF IrDA Device Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/w83977af_ir.h b/drivers/net/irda/w83977af_ir.h
index 87c3975baf62..fefe9b11e200 100644
--- a/drivers/net/irda/w83977af_ir.h
+++ b/drivers/net/irda/w83977af_ir.h
@@ -172,7 +172,6 @@ struct w83977af_ir {
int tx_len; /* Number of frames in tx_buff */
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 binded to */
struct qos_info qos; /* QoS capabilities for this device */
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index c7457f97259d..cb793c2bade2 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -429,7 +429,7 @@ SIMPLE_PORT_ATTR(promiscuous);
SIMPLE_PORT_ATTR(num_mcast);
CUSTOM_PORT_ATTR(lpar_map, "0x%X\n", port->lpar_map);
CUSTOM_PORT_ATTR(stopped_map, "0x%X\n", port->stopped_map);
-CUSTOM_PORT_ATTR(mac_addr, "0x%lX\n", port->mac_addr);
+CUSTOM_PORT_ATTR(mac_addr, "0x%llX\n", port->mac_addr);
#define GET_PORT_ATTR(_name) (&veth_port_attr_##_name.attr)
static struct attribute *veth_port_default_attrs[] = {
diff --git a/drivers/net/korina.c b/drivers/net/korina.c
index 4a5580c1126a..1d6e48e13366 100644
--- a/drivers/net/korina.c
+++ b/drivers/net/korina.c
@@ -84,7 +84,10 @@
#define KORINA_NUM_RDS 64 /* number of receive descriptors */
#define KORINA_NUM_TDS 64 /* number of transmit descriptors */
-#define KORINA_RBSIZE 536 /* size of one resource buffer = Ether MTU */
+/* KORINA_RBSIZE is the hardware's default maximum receive
+ * frame size in bytes. Having this hardcoded means that there
+ * is no support for MTU sizes greater than 1500. */
+#define KORINA_RBSIZE 1536 /* size of one resource buffer = Ether MTU */
#define KORINA_RDS_MASK (KORINA_NUM_RDS - 1)
#define KORINA_TDS_MASK (KORINA_NUM_TDS - 1)
#define RD_RING_SIZE (KORINA_NUM_RDS * sizeof(struct dma_desc))
@@ -196,7 +199,7 @@ static int korina_send_packet(struct sk_buff *skb, struct net_device *dev)
struct korina_private *lp = netdev_priv(dev);
unsigned long flags;
u32 length;
- u32 chain_index;
+ u32 chain_prev, chain_next;
struct dma_desc *td;
spin_lock_irqsave(&lp->lock, flags);
@@ -228,8 +231,8 @@ static int korina_send_packet(struct sk_buff *skb, struct net_device *dev)
/* Setup the transmit descriptor. */
dma_cache_inv((u32) td, sizeof(*td));
td->ca = CPHYSADDR(skb->data);
- chain_index = (lp->tx_chain_tail - 1) &
- KORINA_TDS_MASK;
+ chain_prev = (lp->tx_chain_tail - 1) & KORINA_TDS_MASK;
+ chain_next = (lp->tx_chain_tail + 1) & KORINA_TDS_MASK;
if (readl(&(lp->tx_dma_regs->dmandptr)) == 0) {
if (lp->tx_chain_status == desc_empty) {
@@ -237,7 +240,7 @@ static int korina_send_packet(struct sk_buff *skb, struct net_device *dev)
td->control = DMA_COUNT(length) |
DMA_DESC_COF | DMA_DESC_IOF;
/* Move tail */
- lp->tx_chain_tail = chain_index;
+ lp->tx_chain_tail = chain_next;
/* Write to NDPTR */
writel(CPHYSADDR(&lp->td_ring[lp->tx_chain_head]),
&lp->tx_dma_regs->dmandptr);
@@ -248,12 +251,12 @@ static int korina_send_packet(struct sk_buff *skb, struct net_device *dev)
td->control = DMA_COUNT(length) |
DMA_DESC_COF | DMA_DESC_IOF;
/* Link to prev */
- lp->td_ring[chain_index].control &=
+ lp->td_ring[chain_prev].control &=
~DMA_DESC_COF;
/* Link to prev */
- lp->td_ring[chain_index].link = CPHYSADDR(td);
+ lp->td_ring[chain_prev].link = CPHYSADDR(td);
/* Move tail */
- lp->tx_chain_tail = chain_index;
+ lp->tx_chain_tail = chain_next;
/* Write to NDPTR */
writel(CPHYSADDR(&lp->td_ring[lp->tx_chain_head]),
&(lp->tx_dma_regs->dmandptr));
@@ -267,17 +270,16 @@ static int korina_send_packet(struct sk_buff *skb, struct net_device *dev)
td->control = DMA_COUNT(length) |
DMA_DESC_COF | DMA_DESC_IOF;
/* Move tail */
- lp->tx_chain_tail = chain_index;
+ lp->tx_chain_tail = chain_next;
lp->tx_chain_status = desc_filled;
- netif_stop_queue(dev);
} else {
/* Update tail */
td->control = DMA_COUNT(length) |
DMA_DESC_COF | DMA_DESC_IOF;
- lp->td_ring[chain_index].control &=
+ lp->td_ring[chain_prev].control &=
~DMA_DESC_COF;
- lp->td_ring[chain_index].link = CPHYSADDR(td);
- lp->tx_chain_tail = chain_index;
+ lp->td_ring[chain_prev].link = CPHYSADDR(td);
+ lp->tx_chain_tail = chain_next;
}
}
dma_cache_wback((u32) td, sizeof(*td));
@@ -327,13 +329,13 @@ static irqreturn_t korina_rx_dma_interrupt(int irq, void *dev_id)
dmas = readl(&lp->rx_dma_regs->dmas);
if (dmas & (DMA_STAT_DONE | DMA_STAT_HALT | DMA_STAT_ERR)) {
- netif_rx_schedule_prep(&lp->napi);
-
dmasm = readl(&lp->rx_dma_regs->dmasm);
writel(dmasm | (DMA_STAT_DONE |
DMA_STAT_HALT | DMA_STAT_ERR),
&lp->rx_dma_regs->dmasm);
+ netif_rx_schedule(&lp->napi);
+
if (dmas & DMA_STAT_ERR)
printk(KERN_ERR DRV_NAME "%s: DMA error\n", dev->name);
@@ -350,15 +352,20 @@ static int korina_rx(struct net_device *dev, int limit)
struct dma_desc *rd = &lp->rd_ring[lp->rx_next_done];
struct sk_buff *skb, *skb_new;
u8 *pkt_buf;
- u32 devcs, pkt_len, dmas, rx_free_desc;
+ u32 devcs, pkt_len, dmas;
int count;
dma_cache_inv((u32)rd, sizeof(*rd));
for (count = 0; count < limit; count++) {
+ skb = lp->rx_skb[lp->rx_next_done];
+ skb_new = NULL;
devcs = rd->devcs;
+ if ((KORINA_RBSIZE - (u32)DMA_COUNT(rd->control)) == 0)
+ break;
+
/* Update statistics counters */
if (devcs & ETH_RX_CRC)
dev->stats.rx_crc_errors++;
@@ -381,63 +388,55 @@ static int korina_rx(struct net_device *dev, int limit)
* in Rc32434 (errata ref #077) */
dev->stats.rx_errors++;
dev->stats.rx_dropped++;
- }
-
- while ((rx_free_desc = KORINA_RBSIZE - (u32)DMA_COUNT(rd->control)) != 0) {
- /* init the var. used for the later
- * operations within the while loop */
- skb_new = NULL;
+ } else if ((devcs & ETH_RX_ROK)) {
pkt_len = RCVPKT_LENGTH(devcs);
- skb = lp->rx_skb[lp->rx_next_done];
-
- if ((devcs & ETH_RX_ROK)) {
- /* must be the (first and) last
- * descriptor then */
- pkt_buf = (u8 *)lp->rx_skb[lp->rx_next_done]->data;
-
- /* invalidate the cache */
- dma_cache_inv((unsigned long)pkt_buf, pkt_len - 4);
-
- /* Malloc up new buffer. */
- skb_new = netdev_alloc_skb(dev, KORINA_RBSIZE + 2);
-
- if (!skb_new)
- break;
- /* Do not count the CRC */
- skb_put(skb, pkt_len - 4);
- skb->protocol = eth_type_trans(skb, dev);
-
- /* Pass the packet to upper layers */
- netif_receive_skb(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
-
- /* Update the mcast stats */
- if (devcs & ETH_RX_MP)
- dev->stats.multicast++;
-
- lp->rx_skb[lp->rx_next_done] = skb_new;
- }
-
- rd->devcs = 0;
-
- /* Restore descriptor's curr_addr */
- if (skb_new)
- rd->ca = CPHYSADDR(skb_new->data);
- else
- rd->ca = CPHYSADDR(skb->data);
-
- rd->control = DMA_COUNT(KORINA_RBSIZE) |
- DMA_DESC_COD | DMA_DESC_IOD;
- lp->rd_ring[(lp->rx_next_done - 1) &
- KORINA_RDS_MASK].control &=
- ~DMA_DESC_COD;
-
- lp->rx_next_done = (lp->rx_next_done + 1) & KORINA_RDS_MASK;
- dma_cache_wback((u32)rd, sizeof(*rd));
- rd = &lp->rd_ring[lp->rx_next_done];
- writel(~DMA_STAT_DONE, &lp->rx_dma_regs->dmas);
+
+ /* must be the (first and) last
+ * descriptor then */
+ pkt_buf = (u8 *)lp->rx_skb[lp->rx_next_done]->data;
+
+ /* invalidate the cache */
+ dma_cache_inv((unsigned long)pkt_buf, pkt_len - 4);
+
+ /* Malloc up new buffer. */
+ skb_new = netdev_alloc_skb(dev, KORINA_RBSIZE + 2);
+
+ if (!skb_new)
+ break;
+ /* Do not count the CRC */
+ skb_put(skb, pkt_len - 4);
+ skb->protocol = eth_type_trans(skb, dev);
+
+ /* Pass the packet to upper layers */
+ netif_receive_skb(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
+
+ /* Update the mcast stats */
+ if (devcs & ETH_RX_MP)
+ dev->stats.multicast++;
+
+ lp->rx_skb[lp->rx_next_done] = skb_new;
}
+
+ rd->devcs = 0;
+
+ /* Restore descriptor's curr_addr */
+ if (skb_new)
+ rd->ca = CPHYSADDR(skb_new->data);
+ else
+ rd->ca = CPHYSADDR(skb->data);
+
+ rd->control = DMA_COUNT(KORINA_RBSIZE) |
+ DMA_DESC_COD | DMA_DESC_IOD;
+ lp->rd_ring[(lp->rx_next_done - 1) &
+ KORINA_RDS_MASK].control &=
+ ~DMA_DESC_COD;
+
+ lp->rx_next_done = (lp->rx_next_done + 1) & KORINA_RDS_MASK;
+ dma_cache_wback((u32)rd, sizeof(*rd));
+ rd = &lp->rd_ring[lp->rx_next_done];
+ writel(~DMA_STAT_DONE, &lp->rx_dma_regs->dmas);
}
dmas = readl(&lp->rx_dma_regs->dmas);
@@ -623,12 +622,12 @@ korina_tx_dma_interrupt(int irq, void *dev_id)
dmas = readl(&lp->tx_dma_regs->dmas);
if (dmas & (DMA_STAT_FINI | DMA_STAT_ERR)) {
- korina_tx(dev);
-
dmasm = readl(&lp->tx_dma_regs->dmasm);
writel(dmasm | (DMA_STAT_FINI | DMA_STAT_ERR),
&lp->tx_dma_regs->dmasm);
+ korina_tx(dev);
+
if (lp->tx_chain_status == desc_filled &&
(readl(&(lp->tx_dma_regs->dmandptr)) == 0)) {
writel(CPHYSADDR(&lp->td_ring[lp->tx_chain_head]),
@@ -901,6 +900,8 @@ static int korina_restart(struct net_device *dev)
korina_free_ring(dev);
+ napi_disable(&lp->napi);
+
ret = korina_init(dev);
if (ret < 0) {
printk(KERN_ERR DRV_NAME "%s: cannot restart device\n",
@@ -999,14 +1000,14 @@ static int korina_open(struct net_device *dev)
* that handles the Done Finished
* Ovr and Und Events */
ret = request_irq(lp->rx_irq, &korina_rx_dma_interrupt,
- IRQF_SHARED | IRQF_DISABLED, "Korina ethernet Rx", dev);
+ IRQF_DISABLED, "Korina ethernet Rx", dev);
if (ret < 0) {
printk(KERN_ERR DRV_NAME "%s: unable to get Rx DMA IRQ %d\n",
dev->name, lp->rx_irq);
goto err_release;
}
ret = request_irq(lp->tx_irq, &korina_tx_dma_interrupt,
- IRQF_SHARED | IRQF_DISABLED, "Korina ethernet Tx", dev);
+ IRQF_DISABLED, "Korina ethernet Tx", dev);
if (ret < 0) {
printk(KERN_ERR DRV_NAME "%s: unable to get Tx DMA IRQ %d\n",
dev->name, lp->tx_irq);
@@ -1015,7 +1016,7 @@ static int korina_open(struct net_device *dev)
/* Install handler for overrun error. */
ret = request_irq(lp->ovr_irq, &korina_ovr_interrupt,
- IRQF_SHARED | IRQF_DISABLED, "Ethernet Overflow", dev);
+ IRQF_DISABLED, "Ethernet Overflow", dev);
if (ret < 0) {
printk(KERN_ERR DRV_NAME"%s: unable to get OVR IRQ %d\n",
dev->name, lp->ovr_irq);
@@ -1024,7 +1025,7 @@ static int korina_open(struct net_device *dev)
/* Install handler for underflow error. */
ret = request_irq(lp->und_irq, &korina_und_interrupt,
- IRQF_SHARED | IRQF_DISABLED, "Ethernet Underflow", dev);
+ IRQF_DISABLED, "Ethernet Underflow", dev);
if (ret < 0) {
printk(KERN_ERR DRV_NAME "%s: unable to get UND IRQ %d\n",
dev->name, lp->und_irq);
@@ -1067,6 +1068,8 @@ static int korina_close(struct net_device *dev)
korina_free_ring(dev);
+ napi_disable(&lp->napi);
+
free_irq(lp->rx_irq, dev);
free_irq(lp->tx_irq, dev);
free_irq(lp->ovr_irq, dev);
@@ -1089,7 +1092,6 @@ static int korina_probe(struct platform_device *pdev)
return -ENOMEM;
}
SET_NETDEV_DEV(dev, &pdev->dev);
- platform_set_drvdata(pdev, dev);
lp = netdev_priv(dev);
bif->dev = dev;
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index 57716e22660c..8e884869a05b 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -486,6 +486,7 @@ static const struct net_device_ops mac8390_netdev_ops = {
.ndo_get_stats = ei_get_stats,
.ndo_set_multicast_list = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ei_poll,
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 15bb38d99304..9f6644a44030 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -952,6 +952,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
.ndo_get_stats = mlx4_en_get_stats,
.ndo_set_multicast_list = mlx4_en_set_multicast,
.ndo_set_mac_address = mlx4_en_set_mac,
+ .ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = mlx4_en_change_mtu,
.ndo_tx_timeout = mlx4_en_tx_timeout,
.ndo_vlan_rx_register = mlx4_en_vlan_rx_register,
diff --git a/drivers/net/mlx4/en_params.c b/drivers/net/mlx4/en_params.c
index cfeef0f1bacc..c1bd040b9e05 100644
--- a/drivers/net/mlx4/en_params.c
+++ b/drivers/net/mlx4/en_params.c
@@ -399,8 +399,10 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
rx_size = roundup_pow_of_two(param->rx_pending);
rx_size = max_t(u32, rx_size, MLX4_EN_MIN_RX_SIZE);
+ rx_size = min_t(u32, rx_size, MLX4_EN_MAX_RX_SIZE);
tx_size = roundup_pow_of_two(param->tx_pending);
tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE);
+ tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE);
if (rx_size == priv->prof->rx_ring_size &&
tx_size == priv->prof->tx_ring_size)
@@ -440,8 +442,8 @@ static void mlx4_en_get_ringparam(struct net_device *dev,
struct mlx4_en_dev *mdev = priv->mdev;
memset(param, 0, sizeof(*param));
- param->rx_max_pending = mdev->dev->caps.max_rq_sg;
- param->tx_max_pending = mdev->dev->caps.max_sq_sg;
+ param->rx_max_pending = MLX4_EN_MAX_RX_SIZE;
+ param->tx_max_pending = MLX4_EN_MAX_TX_SIZE;
param->rx_pending = mdev->profile.prof[priv->port].rx_ring_size;
param->tx_pending = mdev->profile.prof[priv->port].tx_ring_size;
}
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c
index ff4d75205c25..4afd5993e31c 100644
--- a/drivers/net/mlx4/en_tx.c
+++ b/drivers/net/mlx4/en_tx.c
@@ -203,19 +203,21 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
/* Optimize the common case when there are no wraparounds */
if (likely((void *) tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) {
- if (tx_info->linear) {
- pci_unmap_single(mdev->pdev,
- (dma_addr_t) be64_to_cpu(data->addr),
+ if (!tx_info->inl) {
+ if (tx_info->linear) {
+ pci_unmap_single(mdev->pdev,
+ (dma_addr_t) be64_to_cpu(data->addr),
be32_to_cpu(data->byte_count),
PCI_DMA_TODEVICE);
- ++data;
- }
+ ++data;
+ }
- for (i = 0; i < frags; i++) {
- frag = &skb_shinfo(skb)->frags[i];
- pci_unmap_page(mdev->pdev,
- (dma_addr_t) be64_to_cpu(data[i].addr),
- frag->size, PCI_DMA_TODEVICE);
+ for (i = 0; i < frags; i++) {
+ frag = &skb_shinfo(skb)->frags[i];
+ pci_unmap_page(mdev->pdev,
+ (dma_addr_t) be64_to_cpu(data[i].addr),
+ frag->size, PCI_DMA_TODEVICE);
+ }
}
/* Stamp the freed descriptor */
for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) {
@@ -224,27 +226,29 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
}
} else {
- if ((void *) data >= end) {
- data = (struct mlx4_wqe_data_seg *)
- (ring->buf + ((void *) data - end));
- }
+ if (!tx_info->inl) {
+ if ((void *) data >= end) {
+ data = (struct mlx4_wqe_data_seg *)
+ (ring->buf + ((void *) data - end));
+ }
- if (tx_info->linear) {
- pci_unmap_single(mdev->pdev,
- (dma_addr_t) be64_to_cpu(data->addr),
+ if (tx_info->linear) {
+ pci_unmap_single(mdev->pdev,
+ (dma_addr_t) be64_to_cpu(data->addr),
be32_to_cpu(data->byte_count),
PCI_DMA_TODEVICE);
- ++data;
- }
+ ++data;
+ }
- for (i = 0; i < frags; i++) {
- /* Check for wraparound before unmapping */
- if ((void *) data >= end)
- data = (struct mlx4_wqe_data_seg *) ring->buf;
- frag = &skb_shinfo(skb)->frags[i];
- pci_unmap_page(mdev->pdev,
+ for (i = 0; i < frags; i++) {
+ /* Check for wraparound before unmapping */
+ if ((void *) data >= end)
+ data = (struct mlx4_wqe_data_seg *) ring->buf;
+ frag = &skb_shinfo(skb)->frags[i];
+ pci_unmap_page(mdev->pdev,
(dma_addr_t) be64_to_cpu(data->addr),
frag->size, PCI_DMA_TODEVICE);
+ }
}
/* Stamp the freed descriptor */
for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) {
@@ -790,8 +794,11 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
wmb();
data->byte_count = cpu_to_be32(skb_headlen(skb) - lso_header_size);
}
- } else
+ tx_info->inl = 0;
+ } else {
build_inline_wqe(tx_desc, skb, real_size, &vlan_tag, tx_ind, fragptr);
+ tx_info->inl = 1;
+ }
ring->prod += nr_txbb;
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 710c79e7a2db..6ef2490d5c3e 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -912,8 +912,8 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
int i;
if (msi_x) {
- nreq = min(dev->caps.num_eqs - dev->caps.reserved_eqs,
- num_possible_cpus() + 1);
+ nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs,
+ num_possible_cpus() + 1);
entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL);
if (!entries)
goto no_msi;
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h
index 2e96c7b2180a..e9af32d41ca4 100644
--- a/drivers/net/mlx4/mlx4_en.h
+++ b/drivers/net/mlx4/mlx4_en.h
@@ -115,6 +115,10 @@ enum {
};
#define MLX4_EN_MAX_RX_FRAGS 4
+/* Maximum ring sizes */
+#define MLX4_EN_MAX_TX_SIZE 8192
+#define MLX4_EN_MAX_RX_SIZE 8192
+
/* Minimum ring size for our page-allocation sceme to work */
#define MLX4_EN_MIN_RX_SIZE (MLX4_EN_ALLOC_SIZE / SMP_CACHE_BYTES)
#define MLX4_EN_MIN_TX_SIZE (4096 / TXBB_SIZE)
@@ -202,6 +206,7 @@ struct mlx4_en_tx_info {
u32 nr_txbb;
u8 linear;
u8 data_offset;
+ u8 inl;
};
diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c
index 919fb9eb1b62..cebdf3243ca1 100644
--- a/drivers/net/mlx4/profile.c
+++ b/drivers/net/mlx4/profile.c
@@ -107,9 +107,9 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
profile[MLX4_RES_AUXC].num = request->num_qp;
profile[MLX4_RES_SRQ].num = request->num_srq;
profile[MLX4_RES_CQ].num = request->num_cq;
- profile[MLX4_RES_EQ].num = min(dev_cap->max_eqs,
- dev_cap->reserved_eqs +
- num_possible_cpus() + 1);
+ profile[MLX4_RES_EQ].num = min_t(unsigned, dev_cap->max_eqs,
+ dev_cap->reserved_eqs +
+ num_possible_cpus() + 1);
profile[MLX4_RES_DMPT].num = request->num_mpt;
profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS;
profile[MLX4_RES_MTT].num = request->num_mtt;
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 478edb92bca3..c5dec54251bf 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -779,6 +779,22 @@ static void __devinit natsemi_init_media (struct net_device *dev)
}
+static const struct net_device_ops natsemi_netdev_ops = {
+ .ndo_open = netdev_open,
+ .ndo_stop = netdev_close,
+ .ndo_start_xmit = start_tx,
+ .ndo_get_stats = get_stats,
+ .ndo_set_multicast_list = set_rx_mode,
+ .ndo_change_mtu = natsemi_change_mtu,
+ .ndo_do_ioctl = netdev_ioctl,
+ .ndo_tx_timeout = ns_tx_timeout,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = natsemi_poll_controller,
+#endif
+};
+
static int __devinit natsemi_probe1 (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -911,20 +927,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
if (find_cnt < MAX_UNITS && full_duplex[find_cnt])
np->full_duplex = 1;
- /* The chip-specific entries in the device structure. */
- dev->open = &netdev_open;
- dev->hard_start_xmit = &start_tx;
- dev->stop = &netdev_close;
- dev->get_stats = &get_stats;
- dev->set_multicast_list = &set_rx_mode;
- dev->change_mtu = &natsemi_change_mtu;
- dev->do_ioctl = &netdev_ioctl;
- dev->tx_timeout = &ns_tx_timeout;
+ dev->netdev_ops = &natsemi_netdev_ops;
dev->watchdog_timeo = TX_TIMEOUT;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = &natsemi_poll_controller;
-#endif
SET_ETHTOOL_OPS(dev, &ethtool_ops);
if (mtu)
diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c
index b57239171046..7bd6662d5b04 100644
--- a/drivers/net/ne-h8300.c
+++ b/drivers/net/ne-h8300.c
@@ -202,6 +202,7 @@ static const struct net_device_ops ne_netdev_ops = {
.ndo_get_stats = ei_get_stats,
.ndo_set_multicast_list = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ei_poll,
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index 62f20ba211cb..f090d3b9ec94 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -208,6 +208,7 @@ static const struct net_device_ops ne2k_netdev_ops = {
.ndo_get_stats = ei_get_stats,
.ndo_set_multicast_list = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ei_poll,
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index f8e601c51da7..c11c568fd7db 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -308,27 +308,16 @@ struct netxen_ring_ctx {
#define netxen_set_cmd_desc_ctxid(cmd_desc, var) \
((cmd_desc)->port_ctxid |= ((var) << 4 & 0xF0))
-#define netxen_set_cmd_desc_flags(cmd_desc, val) \
- (cmd_desc)->flags_opcode = ((cmd_desc)->flags_opcode & \
- ~cpu_to_le16(0x7f)) | cpu_to_le16((val) & 0x7f)
-#define netxen_set_cmd_desc_opcode(cmd_desc, val) \
- (cmd_desc)->flags_opcode = ((cmd_desc)->flags_opcode & \
- ~cpu_to_le16((u16)0x3f << 7)) | cpu_to_le16(((val) & 0x3f) << 7)
-
-#define netxen_set_cmd_desc_num_of_buff(cmd_desc, val) \
- (cmd_desc)->num_of_buffers_total_length = \
- ((cmd_desc)->num_of_buffers_total_length & \
- ~cpu_to_le32(0xff)) | cpu_to_le32((val) & 0xff)
-#define netxen_set_cmd_desc_totallength(cmd_desc, val) \
- (cmd_desc)->num_of_buffers_total_length = \
- ((cmd_desc)->num_of_buffers_total_length & \
- ~cpu_to_le32((u32)0xffffff << 8)) | \
- cpu_to_le32(((val) & 0xffffff) << 8)
-
-#define netxen_get_cmd_desc_opcode(cmd_desc) \
- ((le16_to_cpu((cmd_desc)->flags_opcode) >> 7) & 0x003f)
-#define netxen_get_cmd_desc_totallength(cmd_desc) \
- ((le32_to_cpu((cmd_desc)->num_of_buffers_total_length) >> 8) & 0xffffff)
+#define netxen_set_tx_port(_desc, _port) \
+ (_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0)
+
+#define netxen_set_tx_flags_opcode(_desc, _flags, _opcode) \
+ (_desc)->flags_opcode = \
+ cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7))
+
+#define netxen_set_tx_frags_len(_desc, _frags, _len) \
+ (_desc)->num_of_buffers_total_length = \
+ cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8))
struct cmd_desc_type0 {
u8 tcp_hdr_offset; /* For LSO only */
@@ -510,7 +499,8 @@ typedef enum {
NETXEN_BRDTYPE_P3_10G_SFP_CT = 0x002a,
NETXEN_BRDTYPE_P3_10G_SFP_QT = 0x002b,
NETXEN_BRDTYPE_P3_10G_CX4 = 0x0031,
- NETXEN_BRDTYPE_P3_10G_XFP = 0x0032
+ NETXEN_BRDTYPE_P3_10G_XFP = 0x0032,
+ NETXEN_BRDTYPE_P3_10G_TP = 0x0080
} netxen_brdtype_t;
@@ -757,7 +747,7 @@ extern char netxen_nic_driver_name[];
*/
struct netxen_skb_frag {
u64 dma;
- u32 length;
+ ulong length;
};
#define _netxen_set_bits(config_word, start, bits, val) {\
@@ -783,13 +773,7 @@ struct netxen_skb_frag {
struct netxen_cmd_buffer {
struct sk_buff *skb;
struct netxen_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1];
- u32 total_length;
- u32 mss;
- u16 port;
- u8 cmd;
- u8 frag_count;
- unsigned long time_stamp;
- u32 state;
+ u32 frag_count;
};
/* In rx_buffer, we do not need multiple fragments as is a single buffer */
@@ -876,7 +860,6 @@ struct nx_host_rds_ring {
u32 skb_size;
struct netxen_rx_buffer *rx_buf_arr; /* rx buffers for receive */
struct list_head free_list;
- int begin_alloc;
};
/*
@@ -995,31 +978,31 @@ struct netxen_recv_context {
*/
typedef struct {
- u64 host_phys_addr; /* Ring base addr */
- u32 ring_size; /* Ring entries */
- u16 msi_index;
- u16 rsvd; /* Padding */
+ __le64 host_phys_addr; /* Ring base addr */
+ __le32 ring_size; /* Ring entries */
+ __le16 msi_index;
+ __le16 rsvd; /* Padding */
} nx_hostrq_sds_ring_t;
typedef struct {
- u64 host_phys_addr; /* Ring base addr */
- u64 buff_size; /* Packet buffer size */
- u32 ring_size; /* Ring entries */
- u32 ring_kind; /* Class of ring */
+ __le64 host_phys_addr; /* Ring base addr */
+ __le64 buff_size; /* Packet buffer size */
+ __le32 ring_size; /* Ring entries */
+ __le32 ring_kind; /* Class of ring */
} nx_hostrq_rds_ring_t;
typedef struct {
- u64 host_rsp_dma_addr; /* Response dma'd here */
- u32 capabilities[4]; /* Flag bit vector */
- u32 host_int_crb_mode; /* Interrupt crb usage */
- u32 host_rds_crb_mode; /* RDS crb usage */
+ __le64 host_rsp_dma_addr; /* Response dma'd here */
+ __le32 capabilities[4]; /* Flag bit vector */
+ __le32 host_int_crb_mode; /* Interrupt crb usage */
+ __le32 host_rds_crb_mode; /* RDS crb usage */
/* These ring offsets are relative to data[0] below */
- u32 rds_ring_offset; /* Offset to RDS config */
- u32 sds_ring_offset; /* Offset to SDS config */
- u16 num_rds_rings; /* Count of RDS rings */
- u16 num_sds_rings; /* Count of SDS rings */
- u16 rsvd1; /* Padding */
- u16 rsvd2; /* Padding */
+ __le32 rds_ring_offset; /* Offset to RDS config */
+ __le32 sds_ring_offset; /* Offset to SDS config */
+ __le16 num_rds_rings; /* Count of RDS rings */
+ __le16 num_sds_rings; /* Count of SDS rings */
+ __le16 rsvd1; /* Padding */
+ __le16 rsvd2; /* Padding */
u8 reserved[128]; /* reserve space for future expansion*/
/* MUST BE 64-bit aligned.
The following is packed:
@@ -1029,24 +1012,24 @@ typedef struct {
} nx_hostrq_rx_ctx_t;
typedef struct {
- u32 host_producer_crb; /* Crb to use */
- u32 rsvd1; /* Padding */
+ __le32 host_producer_crb; /* Crb to use */
+ __le32 rsvd1; /* Padding */
} nx_cardrsp_rds_ring_t;
typedef struct {
- u32 host_consumer_crb; /* Crb to use */
- u32 interrupt_crb; /* Crb to use */
+ __le32 host_consumer_crb; /* Crb to use */
+ __le32 interrupt_crb; /* Crb to use */
} nx_cardrsp_sds_ring_t;
typedef struct {
/* These ring offsets are relative to data[0] below */
- u32 rds_ring_offset; /* Offset to RDS config */
- u32 sds_ring_offset; /* Offset to SDS config */
- u32 host_ctx_state; /* Starting State */
- u32 num_fn_per_port; /* How many PCI fn share the port */
- u16 num_rds_rings; /* Count of RDS rings */
- u16 num_sds_rings; /* Count of SDS rings */
- u16 context_id; /* Handle for context */
+ __le32 rds_ring_offset; /* Offset to RDS config */
+ __le32 sds_ring_offset; /* Offset to SDS config */
+ __le32 host_ctx_state; /* Starting State */
+ __le32 num_fn_per_port; /* How many PCI fn share the port */
+ __le16 num_rds_rings; /* Count of RDS rings */
+ __le16 num_sds_rings; /* Count of SDS rings */
+ __le16 context_id; /* Handle for context */
u8 phys_port; /* Physical id of port */
u8 virt_port; /* Virtual/Logical id of port */
u8 reserved[128]; /* save space for future expansion */
@@ -1072,34 +1055,34 @@ typedef struct {
*/
typedef struct {
- u64 host_phys_addr; /* Ring base addr */
- u32 ring_size; /* Ring entries */
- u32 rsvd; /* Padding */
+ __le64 host_phys_addr; /* Ring base addr */
+ __le32 ring_size; /* Ring entries */
+ __le32 rsvd; /* Padding */
} nx_hostrq_cds_ring_t;
typedef struct {
- u64 host_rsp_dma_addr; /* Response dma'd here */
- u64 cmd_cons_dma_addr; /* */
- u64 dummy_dma_addr; /* */
- u32 capabilities[4]; /* Flag bit vector */
- u32 host_int_crb_mode; /* Interrupt crb usage */
- u32 rsvd1; /* Padding */
- u16 rsvd2; /* Padding */
- u16 interrupt_ctl;
- u16 msi_index;
- u16 rsvd3; /* Padding */
+ __le64 host_rsp_dma_addr; /* Response dma'd here */
+ __le64 cmd_cons_dma_addr; /* */
+ __le64 dummy_dma_addr; /* */
+ __le32 capabilities[4]; /* Flag bit vector */
+ __le32 host_int_crb_mode; /* Interrupt crb usage */
+ __le32 rsvd1; /* Padding */
+ __le16 rsvd2; /* Padding */
+ __le16 interrupt_ctl;
+ __le16 msi_index;
+ __le16 rsvd3; /* Padding */
nx_hostrq_cds_ring_t cds_ring; /* Desc of cds ring */
u8 reserved[128]; /* future expansion */
} nx_hostrq_tx_ctx_t;
typedef struct {
- u32 host_producer_crb; /* Crb to use */
- u32 interrupt_crb; /* Crb to use */
+ __le32 host_producer_crb; /* Crb to use */
+ __le32 interrupt_crb; /* Crb to use */
} nx_cardrsp_cds_ring_t;
typedef struct {
- u32 host_ctx_state; /* Starting state */
- u16 context_id; /* Handle for context */
+ __le32 host_ctx_state; /* Starting state */
+ __le16 context_id; /* Handle for context */
u8 phys_port; /* Physical id of port */
u8 virt_port; /* Virtual/Logical id of port */
nx_cardrsp_cds_ring_t cds_ring; /* Card cds settings */
@@ -1202,9 +1185,9 @@ enum {
#define VPORT_MISS_MODE_ACCEPT_MULTI 2 /* accept unmatched multicast */
typedef struct {
- u64 qhdr;
- u64 req_hdr;
- u64 words[6];
+ __le64 qhdr;
+ __le64 req_hdr;
+ __le64 words[6];
} nx_nic_req_t;
typedef struct {
@@ -1486,8 +1469,6 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter);
void netxen_initialize_adapter_ops(struct netxen_adapter *adapter);
int netxen_init_firmware(struct netxen_adapter *adapter);
-void netxen_tso_check(struct netxen_adapter *adapter,
- struct cmd_desc_type0 *desc, struct sk_buff *skb);
void netxen_nic_clear_stats(struct netxen_adapter *adapter);
void netxen_watchdog_task(struct work_struct *work);
void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx,
@@ -1496,6 +1477,7 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter);
u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctx, int max);
void netxen_p2_nic_set_multi(struct net_device *netdev);
void netxen_p3_nic_set_multi(struct net_device *netdev);
+void netxen_p3_free_mac_list(struct netxen_adapter *adapter);
int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32);
int netxen_config_intr_coalesce(struct netxen_adapter *adapter);
diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c
index 64b51643c626..746bdb470418 100644
--- a/drivers/net/netxen/netxen_nic_ctx.c
+++ b/drivers/net/netxen/netxen_nic_ctx.c
@@ -76,7 +76,7 @@ netxen_api_unlock(struct netxen_adapter *adapter)
static u32
netxen_poll_rsp(struct netxen_adapter *adapter)
{
- u32 raw_rsp, rsp = NX_CDRP_RSP_OK;
+ u32 rsp = NX_CDRP_RSP_OK;
int timeout = 0;
do {
@@ -86,10 +86,7 @@ netxen_poll_rsp(struct netxen_adapter *adapter)
if (++timeout > NX_OS_CRB_RETRY_COUNT)
return NX_CDRP_RSP_TIMEOUT;
- netxen_nic_read_w1(adapter, NX_CDRP_CRB_OFFSET,
- &raw_rsp);
-
- rsp = le32_to_cpu(raw_rsp);
+ netxen_nic_read_w1(adapter, NX_CDRP_CRB_OFFSET, &rsp);
} while (!NX_CDRP_IS_RSP(rsp));
return rsp;
@@ -109,20 +106,16 @@ netxen_issue_cmd(struct netxen_adapter *adapter,
if (netxen_api_lock(adapter))
return NX_RCODE_TIMEOUT;
- netxen_nic_write_w1(adapter, NX_SIGN_CRB_OFFSET,
- cpu_to_le32(signature));
+ netxen_nic_write_w1(adapter, NX_SIGN_CRB_OFFSET, signature);
- netxen_nic_write_w1(adapter, NX_ARG1_CRB_OFFSET,
- cpu_to_le32(arg1));
+ netxen_nic_write_w1(adapter, NX_ARG1_CRB_OFFSET, arg1);
- netxen_nic_write_w1(adapter, NX_ARG2_CRB_OFFSET,
- cpu_to_le32(arg2));
+ netxen_nic_write_w1(adapter, NX_ARG2_CRB_OFFSET, arg2);
- netxen_nic_write_w1(adapter, NX_ARG3_CRB_OFFSET,
- cpu_to_le32(arg3));
+ netxen_nic_write_w1(adapter, NX_ARG3_CRB_OFFSET, arg3);
netxen_nic_write_w1(adapter, NX_CDRP_CRB_OFFSET,
- cpu_to_le32(NX_CDRP_FORM_CMD(cmd)));
+ NX_CDRP_FORM_CMD(cmd));
rsp = netxen_poll_rsp(adapter);
@@ -133,7 +126,6 @@ netxen_issue_cmd(struct netxen_adapter *adapter,
rcode = NX_RCODE_TIMEOUT;
} else if (rsp == NX_CDRP_RSP_FAIL) {
netxen_nic_read_w1(adapter, NX_ARG1_CRB_OFFSET, &rcode);
- rcode = le32_to_cpu(rcode);
printk(KERN_ERR "%s: failed card response code:0x%x\n",
netxen_nic_driver_name, rcode);
@@ -183,7 +175,7 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
int i, nrds_rings, nsds_rings;
size_t rq_size, rsp_size;
- u32 cap, reg;
+ u32 cap, reg, val;
int err;
@@ -225,11 +217,14 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
prq->num_rds_rings = cpu_to_le16(nrds_rings);
prq->num_sds_rings = cpu_to_le16(nsds_rings);
- prq->rds_ring_offset = 0;
- prq->sds_ring_offset = prq->rds_ring_offset +
+ prq->rds_ring_offset = cpu_to_le32(0);
+
+ val = le32_to_cpu(prq->rds_ring_offset) +
(sizeof(nx_hostrq_rds_ring_t) * nrds_rings);
+ prq->sds_ring_offset = cpu_to_le32(val);
- prq_rds = (nx_hostrq_rds_ring_t *)(prq->data + prq->rds_ring_offset);
+ prq_rds = (nx_hostrq_rds_ring_t *)(prq->data +
+ le32_to_cpu(prq->rds_ring_offset));
for (i = 0; i < nrds_rings; i++) {
@@ -241,17 +236,14 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
prq_rds[i].buff_size = cpu_to_le64(rds_ring->dma_size);
}
- prq_sds = (nx_hostrq_sds_ring_t *)(prq->data + prq->sds_ring_offset);
+ prq_sds = (nx_hostrq_sds_ring_t *)(prq->data +
+ le32_to_cpu(prq->sds_ring_offset));
prq_sds[0].host_phys_addr =
cpu_to_le64(recv_ctx->rcv_status_desc_phys_addr);
prq_sds[0].ring_size = cpu_to_le32(adapter->max_rx_desc_count);
/* only one msix vector for now */
- prq_sds[0].msi_index = cpu_to_le32(0);
-
- /* now byteswap offsets */
- prq->rds_ring_offset = cpu_to_le32(prq->rds_ring_offset);
- prq->sds_ring_offset = cpu_to_le32(prq->sds_ring_offset);
+ prq_sds[0].msi_index = cpu_to_le16(0);
phys_addr = hostrq_phys_addr;
err = netxen_issue_cmd(adapter,
@@ -269,9 +261,9 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
prsp_rds = ((nx_cardrsp_rds_ring_t *)
- &prsp->data[prsp->rds_ring_offset]);
+ &prsp->data[le32_to_cpu(prsp->rds_ring_offset)]);
- for (i = 0; i < le32_to_cpu(prsp->num_rds_rings); i++) {
+ for (i = 0; i < le16_to_cpu(prsp->num_rds_rings); i++) {
rds_ring = &recv_ctx->rds_rings[i];
reg = le32_to_cpu(prsp_rds[i].host_producer_crb);
@@ -279,7 +271,7 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
}
prsp_sds = ((nx_cardrsp_sds_ring_t *)
- &prsp->data[prsp->sds_ring_offset]);
+ &prsp->data[le32_to_cpu(prsp->sds_ring_offset)]);
reg = le32_to_cpu(prsp_sds[0].host_consumer_crb);
recv_ctx->crb_sts_consumer = NETXEN_NIC_REG(reg - 0x200);
@@ -288,7 +280,7 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
recv_ctx->state = le32_to_cpu(prsp->host_ctx_state);
recv_ctx->context_id = le16_to_cpu(prsp->context_id);
- recv_ctx->virt_port = le16_to_cpu(prsp->virt_port);
+ recv_ctx->virt_port = prsp->virt_port;
out_free_rsp:
pci_free_consistent(adapter->pdev, rsp_size, prsp, cardrsp_phys_addr);
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index e45ce2951729..c0bd40fcf708 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -136,11 +136,9 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->port = PORT_TP;
- if (netif_running(dev)) {
- ecmd->speed = adapter->link_speed;
- ecmd->duplex = adapter->link_duplex;
- ecmd->autoneg = adapter->link_autoneg;
- }
+ ecmd->speed = adapter->link_speed;
+ ecmd->duplex = adapter->link_duplex;
+ ecmd->autoneg = adapter->link_autoneg;
} else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
u32 val;
@@ -171,7 +169,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
} else
return -EIO;
- ecmd->phy_address = adapter->portnum;
+ ecmd->phy_address = adapter->physical_port;
ecmd->transceiver = XCVR_EXTERNAL;
switch ((netxen_brdtype_t) boardinfo->board_type) {
@@ -180,13 +178,13 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
case NETXEN_BRDTYPE_P3_REF_QG:
case NETXEN_BRDTYPE_P3_4_GB:
case NETXEN_BRDTYPE_P3_4_GB_MM:
- case NETXEN_BRDTYPE_P3_10000_BASE_T:
ecmd->supported |= SUPPORTED_Autoneg;
ecmd->advertising |= ADVERTISED_Autoneg;
case NETXEN_BRDTYPE_P2_SB31_10G_CX4:
case NETXEN_BRDTYPE_P3_10G_CX4:
case NETXEN_BRDTYPE_P3_10G_CX4_LP:
+ case NETXEN_BRDTYPE_P3_10000_BASE_T:
ecmd->supported |= SUPPORTED_TP;
ecmd->advertising |= ADVERTISED_TP;
ecmd->port = PORT_TP;
@@ -204,16 +202,33 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->port = PORT_FIBRE;
ecmd->autoneg = AUTONEG_DISABLE;
break;
- case NETXEN_BRDTYPE_P2_SB31_10G:
case NETXEN_BRDTYPE_P3_10G_SFP_PLUS:
case NETXEN_BRDTYPE_P3_10G_SFP_CT:
case NETXEN_BRDTYPE_P3_10G_SFP_QT:
+ ecmd->advertising |= ADVERTISED_TP;
+ ecmd->supported |= SUPPORTED_TP;
+ case NETXEN_BRDTYPE_P2_SB31_10G:
case NETXEN_BRDTYPE_P3_10G_XFP:
ecmd->supported |= SUPPORTED_FIBRE;
ecmd->advertising |= ADVERTISED_FIBRE;
ecmd->port = PORT_FIBRE;
ecmd->autoneg = AUTONEG_DISABLE;
break;
+ case NETXEN_BRDTYPE_P3_10G_TP:
+ if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+ ecmd->autoneg = AUTONEG_DISABLE;
+ ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
+ ecmd->advertising |=
+ (ADVERTISED_FIBRE | ADVERTISED_TP);
+ ecmd->port = PORT_FIBRE;
+ } else {
+ ecmd->autoneg = AUTONEG_ENABLE;
+ ecmd->supported |= (SUPPORTED_TP |SUPPORTED_Autoneg);
+ ecmd->advertising |=
+ (ADVERTISED_TP | ADVERTISED_Autoneg);
+ ecmd->port = PORT_TP;
+ }
+ break;
default:
printk(KERN_ERR "netxen-nic: Unsupported board model %d\n",
(netxen_brdtype_t) boardinfo->board_type);
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index aa6e603bfcbf..821cff68b3f3 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -503,17 +503,15 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter,
i = 0;
+ netif_tx_lock_bh(adapter->netdev);
+
producer = adapter->cmd_producer;
do {
cmd_desc = &cmd_desc_arr[i];
pbuf = &adapter->cmd_buf_arr[producer];
- pbuf->mss = 0;
- pbuf->total_length = 0;
pbuf->skb = NULL;
- pbuf->cmd = 0;
pbuf->frag_count = 0;
- pbuf->port = 0;
/* adapter->ahw.cmd_desc_head[producer] = *cmd_desc; */
memcpy(&adapter->ahw.cmd_desc_head[producer],
@@ -531,6 +529,8 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter,
netxen_nic_update_cmd_producer(adapter, adapter->cmd_producer);
+ netif_tx_unlock_bh(adapter->netdev);
+
return 0;
}
@@ -539,16 +539,19 @@ static int nx_p3_sre_macaddr_change(struct net_device *dev,
{
struct netxen_adapter *adapter = netdev_priv(dev);
nx_nic_req_t req;
- nx_mac_req_t mac_req;
+ nx_mac_req_t *mac_req;
+ u64 word;
int rv;
memset(&req, 0, sizeof(nx_nic_req_t));
- req.qhdr |= (NX_NIC_REQUEST << 23);
- req.req_hdr |= NX_MAC_EVENT;
- req.req_hdr |= ((u64)adapter->portnum << 16);
- mac_req.op = op;
- memcpy(&mac_req.mac_addr, addr, 6);
- req.words[0] = cpu_to_le64(*(u64 *)&mac_req);
+ req.qhdr = cpu_to_le64(NX_NIC_REQUEST << 23);
+
+ word = NX_MAC_EVENT | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+
+ mac_req = (nx_mac_req_t *)&req.words[0];
+ mac_req->op = op;
+ memcpy(mac_req->mac_addr, addr, 6);
rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
if (rv != 0) {
@@ -612,18 +615,35 @@ send_fw_cmd:
int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32 mode)
{
nx_nic_req_t req;
+ u64 word;
memset(&req, 0, sizeof(nx_nic_req_t));
- req.qhdr |= (NX_HOST_REQUEST << 23);
- req.req_hdr |= NX_NIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE;
- req.req_hdr |= ((u64)adapter->portnum << 16);
+ req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23);
+
+ word = NX_NIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE |
+ ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+
req.words[0] = cpu_to_le64(mode);
return netxen_send_cmd_descs(adapter,
(struct cmd_desc_type0 *)&req, 1);
}
+void netxen_p3_free_mac_list(struct netxen_adapter *adapter)
+{
+ nx_mac_list_t *cur, *next;
+
+ cur = adapter->mac_list;
+
+ while (cur) {
+ next = cur->next;
+ kfree(cur);
+ cur = next;
+ }
+}
+
#define NETXEN_CONFIG_INTR_COALESCE 3
/*
@@ -632,13 +652,15 @@ int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32 mode)
int netxen_config_intr_coalesce(struct netxen_adapter *adapter)
{
nx_nic_req_t req;
+ u64 word;
int rv;
memset(&req, 0, sizeof(nx_nic_req_t));
- req.qhdr |= (NX_NIC_REQUEST << 23);
- req.req_hdr |= NETXEN_CONFIG_INTR_COALESCE;
- req.req_hdr |= ((u64)adapter->portnum << 16);
+ req.qhdr = cpu_to_le64(NX_NIC_REQUEST << 23);
+
+ word = NETXEN_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
memcpy(&req.words[0], &adapter->coal, sizeof(adapter->coal));
@@ -772,13 +794,10 @@ int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac)
adapter->hw_read_wx(adapter, crbaddr, &mac_lo, 4);
adapter->hw_read_wx(adapter, crbaddr+4, &mac_hi, 4);
- mac_hi = cpu_to_le32(mac_hi);
- mac_lo = cpu_to_le32(mac_lo);
-
if (pci_func & 1)
- *mac = ((mac_lo >> 16) | ((u64)mac_hi << 16));
+ *mac = le64_to_cpu((mac_lo >> 16) | ((u64)mac_hi << 16));
else
- *mac = ((mac_lo) | ((u64)mac_hi << 32));
+ *mac = le64_to_cpu((u64)mac_lo | ((u64)mac_hi << 32));
return 0;
}
@@ -937,7 +956,7 @@ int netxen_load_firmware(struct netxen_adapter *adapter)
{
int i;
u32 data, size = 0;
- u32 flashaddr = NETXEN_BOOTLD_START, memaddr = NETXEN_BOOTLD_START;
+ u32 flashaddr = NETXEN_BOOTLD_START;
size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START)/4;
@@ -949,10 +968,8 @@ int netxen_load_firmware(struct netxen_adapter *adapter)
if (netxen_rom_fast_read(adapter, flashaddr, (int *)&data) != 0)
return -EIO;
- adapter->pci_mem_write(adapter, memaddr, &data, 4);
+ adapter->pci_mem_write(adapter, flashaddr, &data, 4);
flashaddr += 4;
- memaddr += 4;
- cond_resched();
}
msleep(1);
@@ -2034,7 +2051,13 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter)
rv = -1;
}
- DPRINTK(INFO, "Discovered board type:0x%x ", boardinfo->board_type);
+ if (boardinfo->board_type == NETXEN_BRDTYPE_P3_4_GB_MM) {
+ u32 gpio = netxen_nic_reg_read(adapter,
+ NETXEN_ROMUSB_GLB_PAD_GPIO_I);
+ if ((gpio & 0x8000) == 0)
+ boardinfo->board_type = NETXEN_BRDTYPE_P3_10G_TP;
+ }
+
switch ((netxen_brdtype_t) boardinfo->board_type) {
case NETXEN_BRDTYPE_P2_SB35_4G:
adapter->ahw.board_type = NETXEN_NIC_GBE;
@@ -2053,7 +2076,6 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter)
case NETXEN_BRDTYPE_P3_10G_SFP_QT:
case NETXEN_BRDTYPE_P3_10G_XFP:
case NETXEN_BRDTYPE_P3_10000_BASE_T:
-
adapter->ahw.board_type = NETXEN_NIC_XGBE;
break;
case NETXEN_BRDTYPE_P1_BD:
@@ -2063,9 +2085,12 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter)
case NETXEN_BRDTYPE_P3_REF_QG:
case NETXEN_BRDTYPE_P3_4_GB:
case NETXEN_BRDTYPE_P3_4_GB_MM:
-
adapter->ahw.board_type = NETXEN_NIC_GBE;
break;
+ case NETXEN_BRDTYPE_P3_10G_TP:
+ adapter->ahw.board_type = (adapter->portnum < 2) ?
+ NETXEN_NIC_XGBE : NETXEN_NIC_GBE;
+ break;
default:
printk("%s: Unknown(%x)\n", netxen_nic_driver_name,
boardinfo->board_type);
@@ -2110,12 +2135,16 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter)
{
__u32 status;
__u32 autoneg;
- __u32 mode;
__u32 port_mode;
- netxen_nic_read_w0(adapter, NETXEN_NIU_MODE, &mode);
- if (netxen_get_niu_enable_ge(mode)) { /* Gb 10/100/1000 Mbps mode */
+ if (!netif_carrier_ok(adapter->netdev)) {
+ adapter->link_speed = 0;
+ adapter->link_duplex = -1;
+ adapter->link_autoneg = AUTONEG_ENABLE;
+ return;
+ }
+ if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
adapter->hw_read_wx(adapter,
NETXEN_PORT_MODE_ADDR, &port_mode, 4);
if (port_mode == NETXEN_PORT_MODE_802_3_AP) {
@@ -2141,7 +2170,7 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter)
adapter->link_speed = SPEED_1000;
break;
default:
- adapter->link_speed = -1;
+ adapter->link_speed = 0;
break;
}
switch (netxen_get_phy_duplex(status)) {
@@ -2164,7 +2193,7 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter)
goto link_down;
} else {
link_down:
- adapter->link_speed = -1;
+ adapter->link_speed = 0;
adapter->link_duplex = -1;
}
}
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index d924468e506e..ca7c8d8050c9 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -308,7 +308,6 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
}
memset(rds_ring->rx_buf_arr, 0, RCV_BUFFSIZE);
INIT_LIST_HEAD(&rds_ring->free_list);
- rds_ring->begin_alloc = 0;
/*
* Now go through all of them, set reference handles
* and put them in the queues.
@@ -439,6 +438,8 @@ static int netxen_wait_rom_done(struct netxen_adapter *adapter)
long timeout = 0;
long done = 0;
+ cond_resched();
+
while (done == 0) {
done = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_GLB_STATUS);
done &= 2;
@@ -533,12 +534,9 @@ static int do_rom_fast_write(struct netxen_adapter *adapter, int addr,
static int do_rom_fast_read(struct netxen_adapter *adapter,
int addr, int *valp)
{
- cond_resched();
-
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr);
- netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3);
- udelay(100); /* prevent bursting on CRB */
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
+ netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3);
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb);
if (netxen_wait_rom_done(adapter)) {
printk("Error waiting for rom done\n");
@@ -546,7 +544,7 @@ static int do_rom_fast_read(struct netxen_adapter *adapter,
}
/* reset abyte_cnt and dummy_byte_cnt */
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
- udelay(100); /* prevent bursting on CRB */
+ udelay(10);
netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
*valp = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_ROM_RDATA);
@@ -884,14 +882,16 @@ int netxen_flash_unlock(struct netxen_adapter *adapter)
int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
{
int addr, val;
- int i, init_delay = 0;
+ int i, n, init_delay = 0;
struct crb_addr_pair *buf;
- unsigned offset, n;
+ unsigned offset;
u32 off;
/* resetall */
+ rom_lock(adapter);
netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_GLB_SW_RESET,
0xffffffff);
+ netxen_rom_unlock(adapter);
if (verbose) {
if (netxen_rom_fast_read(adapter, NETXEN_BOARDTYPE, &val) == 0)
@@ -910,7 +910,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
if (netxen_rom_fast_read(adapter, 0, &n) != 0 ||
- (n != 0xcafecafeUL) ||
+ (n != 0xcafecafe) ||
netxen_rom_fast_read(adapter, 4, &n) != 0) {
printk(KERN_ERR "%s: ERROR Reading crb_init area: "
"n: %08x\n", netxen_nic_driver_name, n);
@@ -975,6 +975,14 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
/* do not reset PCI */
if (off == (ROMUSB_GLB + 0xbc))
continue;
+ if (off == (ROMUSB_GLB + 0xa8))
+ continue;
+ if (off == (ROMUSB_GLB + 0xc8)) /* core clock */
+ continue;
+ if (off == (ROMUSB_GLB + 0x24)) /* MN clock */
+ continue;
+ if (off == (ROMUSB_GLB + 0x1c)) /* MS clock */
+ continue;
if (off == (NETXEN_CRB_PEG_NET_1 + 0x18))
buf[i].data = 0x1020;
/* skip the function enable register */
@@ -992,23 +1000,21 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
continue;
}
+ init_delay = 1;
/* After writing this register, HW needs time for CRB */
/* to quiet down (else crb_window returns 0xffffffff) */
if (off == NETXEN_ROMUSB_GLB_SW_RESET) {
- init_delay = 1;
+ init_delay = 1000;
if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
/* hold xdma in reset also */
buf[i].data = NETXEN_NIC_XDMA_RESET;
+ buf[i].data = 0x8000ff;
}
}
adapter->hw_write_wx(adapter, off, &buf[i].data, 4);
- if (init_delay == 1) {
- msleep(1000);
- init_delay = 0;
- }
- msleep(1);
+ msleep(init_delay);
}
kfree(buf);
@@ -1277,7 +1283,7 @@ static void netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
dev_kfree_skb_any(skb);
for (i = 0; i < nr_frags; i++) {
- index = frag_desc->frag_handles[i];
+ index = le16_to_cpu(frag_desc->frag_handles[i]);
skb = netxen_process_rxbuf(adapter,
rds_ring, index, cksum);
if (skb)
@@ -1428,7 +1434,6 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
struct rcv_desc *pdesc;
struct netxen_rx_buffer *buffer;
int count = 0;
- int index = 0;
netxen_ctx_msg msg = 0;
dma_addr_t dma;
struct list_head *head;
@@ -1436,7 +1441,6 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
rds_ring = &recv_ctx->rds_rings[ringid];
producer = rds_ring->producer;
- index = rds_ring->begin_alloc;
head = &rds_ring->free_list;
/* We can start writing rx descriptors into the phantom memory. */
@@ -1444,39 +1448,37 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
skb = dev_alloc_skb(rds_ring->skb_size);
if (unlikely(!skb)) {
- rds_ring->begin_alloc = index;
break;
}
+ if (!adapter->ahw.cut_through)
+ skb_reserve(skb, 2);
+
+ dma = pci_map_single(pdev, skb->data,
+ rds_ring->dma_size, PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(pdev, dma)) {
+ dev_kfree_skb_any(skb);
+ break;
+ }
+
+ count++;
buffer = list_entry(head->next, struct netxen_rx_buffer, list);
list_del(&buffer->list);
- count++; /* now there should be no failure */
- pdesc = &rds_ring->desc_head[producer];
-
- if (!adapter->ahw.cut_through)
- skb_reserve(skb, 2);
- /* This will be setup when we receive the
- * buffer after it has been filled FSL TBD TBD
- * skb->dev = netdev;
- */
- dma = pci_map_single(pdev, skb->data, rds_ring->dma_size,
- PCI_DMA_FROMDEVICE);
- pdesc->addr_buffer = cpu_to_le64(dma);
buffer->skb = skb;
buffer->state = NETXEN_BUFFER_BUSY;
buffer->dma = dma;
+
/* make a rcv descriptor */
+ pdesc = &rds_ring->desc_head[producer];
+ pdesc->addr_buffer = cpu_to_le64(dma);
pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
- DPRINTK(INFO, "done writing descripter\n");
- producer =
- get_next_index(producer, rds_ring->max_rx_desc_count);
- index = get_next_index(index, rds_ring->max_rx_desc_count);
+
+ producer = get_next_index(producer, rds_ring->max_rx_desc_count);
}
/* if we did allocate buffers, then write the count to Phantom */
if (count) {
- rds_ring->begin_alloc = index;
rds_ring->producer = producer;
/* Window = 1 */
adapter->pci_write_normalize(adapter,
@@ -1515,49 +1517,50 @@ static void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter,
struct rcv_desc *pdesc;
struct netxen_rx_buffer *buffer;
int count = 0;
- int index = 0;
struct list_head *head;
+ dma_addr_t dma;
rds_ring = &recv_ctx->rds_rings[ringid];
producer = rds_ring->producer;
- index = rds_ring->begin_alloc;
head = &rds_ring->free_list;
/* We can start writing rx descriptors into the phantom memory. */
while (!list_empty(head)) {
skb = dev_alloc_skb(rds_ring->skb_size);
if (unlikely(!skb)) {
- rds_ring->begin_alloc = index;
break;
}
+ if (!adapter->ahw.cut_through)
+ skb_reserve(skb, 2);
+
+ dma = pci_map_single(pdev, skb->data,
+ rds_ring->dma_size, PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(pdev, dma)) {
+ dev_kfree_skb_any(skb);
+ break;
+ }
+
+ count++;
buffer = list_entry(head->next, struct netxen_rx_buffer, list);
list_del(&buffer->list);
- count++; /* now there should be no failure */
- pdesc = &rds_ring->desc_head[producer];
- if (!adapter->ahw.cut_through)
- skb_reserve(skb, 2);
buffer->skb = skb;
buffer->state = NETXEN_BUFFER_BUSY;
- buffer->dma = pci_map_single(pdev, skb->data,
- rds_ring->dma_size,
- PCI_DMA_FROMDEVICE);
+ buffer->dma = dma;
/* make a rcv descriptor */
+ pdesc = &rds_ring->desc_head[producer];
pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
pdesc->addr_buffer = cpu_to_le64(buffer->dma);
- producer =
- get_next_index(producer, rds_ring->max_rx_desc_count);
- index = get_next_index(index, rds_ring->max_rx_desc_count);
- buffer = &rds_ring->rx_buf_arr[index];
+
+ producer = get_next_index(producer, rds_ring->max_rx_desc_count);
}
/* if we did allocate buffers, then write the count to Phantom */
if (count) {
- rds_ring->begin_alloc = index;
rds_ring->producer = producer;
/* Window = 1 */
adapter->pci_write_normalize(adapter,
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index ba01524b5531..d854f07ef4d3 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -39,7 +39,9 @@
#include "netxen_nic_phan_reg.h"
#include <linux/dma-mapping.h>
+#include <linux/if_vlan.h>
#include <net/ip.h>
+#include <linux/ipv6.h>
MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
MODULE_LICENSE("GPL");
@@ -242,7 +244,7 @@ static void netxen_check_options(struct netxen_adapter *adapter)
case NETXEN_BRDTYPE_P3_4_GB:
case NETXEN_BRDTYPE_P3_4_GB_MM:
adapter->msix_supported = !!use_msi_x;
- adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G;
+ adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
break;
case NETXEN_BRDTYPE_P2_SB35_4G:
@@ -251,6 +253,14 @@ static void netxen_check_options(struct netxen_adapter *adapter)
adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
break;
+ case NETXEN_BRDTYPE_P3_10G_TP:
+ adapter->msix_supported = !!use_msi_x;
+ if (adapter->ahw.board_type == NETXEN_NIC_XGBE)
+ adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G;
+ else
+ adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
+ break;
+
default:
adapter->msix_supported = 0;
adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
@@ -271,10 +281,15 @@ static void netxen_check_options(struct netxen_adapter *adapter)
static int
netxen_check_hw_init(struct netxen_adapter *adapter, int first_boot)
{
- int ret = 0;
+ u32 val, timeout;
if (first_boot == 0x55555555) {
/* This is the first boot after power up */
+ adapter->pci_write_normalize(adapter,
+ NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC);
+
+ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ return 0;
/* PCI bus master workaround */
adapter->hw_read_wx(adapter,
@@ -294,18 +309,26 @@ netxen_check_hw_init(struct netxen_adapter *adapter, int first_boot)
/* clear the register for future unloads/loads */
adapter->pci_write_normalize(adapter,
NETXEN_CAM_RAM(0x1fc), 0);
- ret = -1;
+ return -EIO;
}
- if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
- /* Start P2 boot loader */
- adapter->pci_write_normalize(adapter,
- NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC);
- adapter->pci_write_normalize(adapter,
- NETXEN_ROMUSB_GLB_PEGTUNE_DONE, 1);
- }
+ /* Start P2 boot loader */
+ val = adapter->pci_read_normalize(adapter,
+ NETXEN_ROMUSB_GLB_PEGTUNE_DONE);
+ adapter->pci_write_normalize(adapter,
+ NETXEN_ROMUSB_GLB_PEGTUNE_DONE, val | 0x1);
+ timeout = 0;
+ do {
+ msleep(1);
+ val = adapter->pci_read_normalize(adapter,
+ NETXEN_CAM_RAM(0x1fc));
+
+ if (++timeout > 5000)
+ return -EIO;
+
+ } while (val == NETXEN_BDINFO_MAGIC);
}
- return ret;
+ return 0;
}
static void netxen_set_port_mode(struct netxen_adapter *adapter)
@@ -784,8 +807,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
CRB_CMDPEG_STATE, 0);
netxen_pinit_from_rom(adapter, 0);
msleep(1);
- netxen_load_firmware(adapter);
}
+ netxen_load_firmware(adapter);
if (NX_IS_REVISION_P3(revision_id))
netxen_pcie_strap_init(adapter);
@@ -801,13 +824,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
- if ((first_boot == 0x55555555) &&
- (NX_IS_REVISION_P2(revision_id))) {
- /* Unlock the HW, prompting the boot sequence */
- adapter->pci_write_normalize(adapter,
- NETXEN_ROMUSB_GLB_PEGTUNE_DONE, 1);
- }
-
err = netxen_initialize_adapter_offload(adapter);
if (err)
goto err_out_iounmap;
@@ -821,7 +837,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->pci_write_normalize(adapter, CRB_DRIVER_VERSION, i);
/* Handshake with the card before we register the devices. */
- netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+ err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+ if (err)
+ goto err_out_free_offload;
} /* first_driver */
@@ -925,6 +943,7 @@ err_out_disable_msi:
if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
pci_disable_msi(pdev);
+err_out_free_offload:
if (first_driver)
netxen_free_adapter_offload(adapter);
@@ -968,6 +987,9 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
netxen_free_hw_resources(adapter);
netxen_release_rx_buffers(adapter);
netxen_free_sw_resources(adapter);
+
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ netxen_p3_free_mac_list(adapter);
}
if (adapter->portnum == 0)
@@ -983,8 +1005,10 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
iounmap(adapter->ahw.db_base);
iounmap(adapter->ahw.pci_base0);
- iounmap(adapter->ahw.pci_base1);
- iounmap(adapter->ahw.pci_base2);
+ if (adapter->ahw.pci_base1 != NULL)
+ iounmap(adapter->ahw.pci_base1);
+ if (adapter->ahw.pci_base2 != NULL)
+ iounmap(adapter->ahw.pci_base2);
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -1137,29 +1161,64 @@ static int netxen_nic_close(struct net_device *netdev)
return 0;
}
-void netxen_tso_check(struct netxen_adapter *adapter,
+static bool netxen_tso_check(struct net_device *netdev,
struct cmd_desc_type0 *desc, struct sk_buff *skb)
{
- if (desc->mss) {
- desc->total_hdr_length = (sizeof(struct ethhdr) +
- ip_hdrlen(skb) + tcp_hdrlen(skb));
+ bool tso = false;
+ u8 opcode = TX_ETHER_PKT;
- if ((NX_IS_REVISION_P3(adapter->ahw.revision_id)) &&
- (skb->protocol == htons(ETH_P_IPV6)))
- netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO6);
- else
- netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO);
+ if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
+ skb_shinfo(skb)->gso_size > 0) {
+
+ desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+ desc->total_hdr_length =
+ skb_transport_offset(skb) + tcp_hdrlen(skb);
+
+ opcode = (skb->protocol == htons(ETH_P_IPV6)) ?
+ TX_TCP_LSO6 : TX_TCP_LSO;
+ tso = true;
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
- if (ip_hdr(skb)->protocol == IPPROTO_TCP)
- netxen_set_cmd_desc_opcode(desc, TX_TCP_PKT);
- else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
- netxen_set_cmd_desc_opcode(desc, TX_UDP_PKT);
- else
- return;
+ u8 l4proto;
+
+ if (skb->protocol == htons(ETH_P_IP)) {
+ l4proto = ip_hdr(skb)->protocol;
+
+ if (l4proto == IPPROTO_TCP)
+ opcode = TX_TCP_PKT;
+ else if(l4proto == IPPROTO_UDP)
+ opcode = TX_UDP_PKT;
+ } else if (skb->protocol == htons(ETH_P_IPV6)) {
+ l4proto = ipv6_hdr(skb)->nexthdr;
+
+ if (l4proto == IPPROTO_TCP)
+ opcode = TX_TCPV6_PKT;
+ else if(l4proto == IPPROTO_UDP)
+ opcode = TX_UDPV6_PKT;
+ }
}
desc->tcp_hdr_offset = skb_transport_offset(skb);
desc->ip_hdr_offset = skb_network_offset(skb);
+ netxen_set_tx_flags_opcode(desc, 0, opcode);
+ return tso;
+}
+
+static void
+netxen_clean_tx_dma_mapping(struct pci_dev *pdev,
+ struct netxen_cmd_buffer *pbuf, int last)
+{
+ int k;
+ struct netxen_skb_frag *buffrag;
+
+ buffrag = &pbuf->frag_array[0];
+ pci_unmap_single(pdev, buffrag->dma,
+ buffrag->length, PCI_DMA_TODEVICE);
+
+ for (k = 1; k < last; k++) {
+ buffrag = &pbuf->frag_array[k];
+ pci_unmap_page(pdev, buffrag->dma,
+ buffrag->length, PCI_DMA_TODEVICE);
+ }
}
static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
@@ -1167,33 +1226,22 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
struct netxen_adapter *adapter = netdev_priv(netdev);
struct netxen_hardware_context *hw = &adapter->ahw;
unsigned int first_seg_len = skb->len - skb->data_len;
+ struct netxen_cmd_buffer *pbuf;
struct netxen_skb_frag *buffrag;
- unsigned int i;
+ struct cmd_desc_type0 *hwdesc;
+ struct pci_dev *pdev = adapter->pdev;
+ dma_addr_t temp_dma;
+ int i, k;
u32 producer, consumer;
- u32 saved_producer = 0;
- struct cmd_desc_type0 *hwdesc;
- int k;
- struct netxen_cmd_buffer *pbuf = NULL;
- int frag_count;
- int no_of_desc;
+ int frag_count, no_of_desc;
u32 num_txd = adapter->max_tx_desc_count;
+ bool is_tso = false;
frag_count = skb_shinfo(skb)->nr_frags + 1;
/* There 4 fragments per descriptor */
no_of_desc = (frag_count + 3) >> 2;
- if (netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) {
- if (skb_shinfo(skb)->gso_size > 0) {
-
- no_of_desc++;
- if ((ip_hdrlen(skb) + tcp_hdrlen(skb) +
- sizeof(struct ethhdr)) >
- (sizeof(struct cmd_desc_type0) - 2)) {
- no_of_desc++;
- }
- }
- }
producer = adapter->cmd_producer;
smp_mb();
@@ -1205,34 +1253,26 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
/* Copy the descriptors into the hardware */
- saved_producer = producer;
hwdesc = &hw->cmd_desc_head[producer];
memset(hwdesc, 0, sizeof(struct cmd_desc_type0));
/* Take skb->data itself */
pbuf = &adapter->cmd_buf_arr[producer];
- if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
- skb_shinfo(skb)->gso_size > 0) {
- pbuf->mss = skb_shinfo(skb)->gso_size;
- hwdesc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
- } else {
- pbuf->mss = 0;
- hwdesc->mss = 0;
- }
- pbuf->total_length = skb->len;
+
+ is_tso = netxen_tso_check(netdev, hwdesc, skb);
+
pbuf->skb = skb;
- pbuf->cmd = TX_ETHER_PKT;
pbuf->frag_count = frag_count;
- pbuf->port = adapter->portnum;
buffrag = &pbuf->frag_array[0];
- buffrag->dma = pci_map_single(adapter->pdev, skb->data, first_seg_len,
+ temp_dma = pci_map_single(pdev, skb->data, first_seg_len,
PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(pdev, temp_dma))
+ goto drop_packet;
+
+ buffrag->dma = temp_dma;
buffrag->length = first_seg_len;
- netxen_set_cmd_desc_totallength(hwdesc, skb->len);
- netxen_set_cmd_desc_num_of_buff(hwdesc, frag_count);
- netxen_set_cmd_desc_opcode(hwdesc, TX_ETHER_PKT);
+ netxen_set_tx_frags_len(hwdesc, frag_count, skb->len);
+ netxen_set_tx_port(hwdesc, adapter->portnum);
- netxen_set_cmd_desc_port(hwdesc, adapter->portnum);
- netxen_set_cmd_desc_ctxid(hwdesc, adapter->portnum);
hwdesc->buffer1_length = cpu_to_le16(first_seg_len);
hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
@@ -1240,7 +1280,6 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
struct skb_frag_struct *frag;
int len, temp_len;
unsigned long offset;
- dma_addr_t temp_dma;
/* move to next desc. if there is a need */
if ((i & 0x3) == 0) {
@@ -1256,8 +1295,12 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
offset = frag->page_offset;
temp_len = len;
- temp_dma = pci_map_page(adapter->pdev, frag->page, offset,
+ temp_dma = pci_map_page(pdev, frag->page, offset,
len, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(pdev, temp_dma)) {
+ netxen_clean_tx_dma_mapping(pdev, pbuf, i);
+ goto drop_packet;
+ }
buffrag++;
buffrag->dma = temp_dma;
@@ -1285,16 +1328,12 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
producer = get_next_index(producer, num_txd);
- /* might change opcode to TX_TCP_LSO */
- netxen_tso_check(adapter, &hw->cmd_desc_head[saved_producer], skb);
-
/* For LSO, we need to copy the MAC/IP/TCP headers into
* the descriptor ring
*/
- if (netxen_get_cmd_desc_opcode(&hw->cmd_desc_head[saved_producer])
- == TX_TCP_LSO) {
+ if (is_tso) {
int hdr_len, first_hdr_len, more_hdr;
- hdr_len = hw->cmd_desc_head[saved_producer].total_hdr_length;
+ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
if (hdr_len > (sizeof(struct cmd_desc_type0) - 2)) {
first_hdr_len = sizeof(struct cmd_desc_type0) - 2;
more_hdr = 1;
@@ -1336,6 +1375,11 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
netdev->trans_start = jiffies;
return NETDEV_TX_OK;
+
+drop_packet:
+ adapter->stats.txdropped++;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
}
static int netxen_nic_check_temp(struct netxen_adapter *adapter)
@@ -1407,6 +1451,8 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter)
netif_carrier_off(netdev);
netif_stop_queue(netdev);
}
+
+ netxen_nic_set_link_parameters(adapter);
} else if (!adapter->ahw.linkup && linkup) {
printk(KERN_INFO "%s: %s NIC Link is up\n",
netxen_nic_driver_name, netdev->name);
@@ -1415,6 +1461,8 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter)
netif_carrier_on(netdev);
netif_wake_queue(netdev);
}
+
+ netxen_nic_set_link_parameters(adapter);
}
}
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 46b0772489e4..e80294d8cc19 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1956,7 +1956,11 @@ static const struct net_device_ops netdev_ops = {
.ndo_change_mtu = ns83820_change_mtu,
.ndo_set_multicast_list = ns83820_set_multicast,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_tx_timeout = ns83820_tx_timeout,
+#ifdef NS83820_VLAN_ACCEL_SUPPORT
+ .ndo_vlan_rx_register = ns83820_vlan_rx_register,
+#endif
};
static int __devinit ns83820_init_one(struct pci_dev *pci_dev,
@@ -2216,7 +2220,6 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev,
#ifdef NS83820_VLAN_ACCEL_SUPPORT
/* We also support hardware vlan acceleration */
ndev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
- ndev->vlan_rx_register = ns83820_vlan_rx_register;
#endif
if (using_dac) {
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index 5b7a574ce571..d0349e7d73ea 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -712,7 +712,7 @@ static inline void pasemi_mac_rx_error(const struct pasemi_mac *mac,
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",
+ printk(KERN_ERR "pasemi_mac: rx error. macrx %016llx, rx status %llx\n",
macrx, *chan->status);
printk(KERN_ERR "pasemi_mac: rcmdsta %08x ccmdsta %08x\n",
@@ -730,8 +730,8 @@ static inline void pasemi_mac_tx_error(const struct pasemi_mac *mac,
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, *chan->status);
+ printk(KERN_ERR "pasemi_mac: tx error. mactx 0x%016llx, "\
+ "tx status 0x%016llx\n", mactx, *chan->status);
printk(KERN_ERR "pasemi_mac: tcmdsta 0x%08x\n", cmdsta);
}
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 044b7b07f5f4..665a4286da39 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -1568,6 +1568,22 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
return err;
}
+static const struct net_device_ops pcnet32_netdev_ops = {
+ .ndo_open = pcnet32_open,
+ .ndo_stop = pcnet32_close,
+ .ndo_start_xmit = pcnet32_start_xmit,
+ .ndo_tx_timeout = pcnet32_tx_timeout,
+ .ndo_get_stats = pcnet32_get_stats,
+ .ndo_set_multicast_list = pcnet32_set_multicast_list,
+ .ndo_do_ioctl = pcnet32_ioctl,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = pcnet32_poll_controller,
+#endif
+};
+
/* pcnet32_probe1
* Called from both pcnet32_probe_vlbus and pcnet_probe_pci.
* pdev will be NULL when called from pcnet32_probe_vlbus.
@@ -1934,20 +1950,10 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
lp->watchdog_timer.function = (void *)&pcnet32_watchdog;
/* The PCNET32-specific entries in the device structure. */
- dev->open = &pcnet32_open;
- dev->hard_start_xmit = &pcnet32_start_xmit;
- dev->stop = &pcnet32_close;
- dev->get_stats = &pcnet32_get_stats;
- dev->set_multicast_list = &pcnet32_set_multicast_list;
- dev->do_ioctl = &pcnet32_ioctl;
+ dev->netdev_ops = &pcnet32_netdev_ops;
dev->ethtool_ops = &pcnet32_ethtool_ops;
- dev->tx_timeout = pcnet32_tx_timeout;
dev->watchdog_timeo = (5 * HZ);
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = pcnet32_poll_controller;
-#endif
-
/* Fill in the generic fields of the device structure. */
if (register_netdev(dev))
goto err_free_ring;
@@ -2276,7 +2282,7 @@ static int pcnet32_open(struct net_device *dev)
if (lp->chip_version >= PCNET32_79C970A) {
/* Print the link status and start the watchdog */
pcnet32_check_media(dev, 1);
- mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
+ mod_timer(&lp->watchdog_timer, PCNET32_WATCHDOG_TIMEOUT);
}
i = 0;
@@ -2911,7 +2917,7 @@ static void pcnet32_watchdog(struct net_device *dev)
pcnet32_check_media(dev, 0);
spin_unlock_irqrestore(&lp->lock, flags);
- mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
+ mod_timer(&lp->watchdog_timer, round_jiffies(PCNET32_WATCHDOG_TIMEOUT));
}
static int pcnet32_pm_suspend(struct pci_dev *pdev, pm_message_t state)
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index e35460165bf7..0a06e4fd37d9 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -231,15 +231,6 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
if ((phy_id & 0x1fffffff) == 0x1fffffff)
return NULL;
- /*
- * Broken hardware is sometimes missing the pull-up resistor on the
- * MDIO line, which results in reads to non-existent devices returning
- * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent
- * device as well.
- */
- if (phy_id == 0)
- return NULL;
-
dev = phy_device_create(bus, addr, phy_id);
return dev;
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 0c46d603b8fe..0be0f0b164f3 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -265,6 +265,13 @@ static const struct header_ops plip_header_ops = {
.cache = plip_hard_header_cache,
};
+static const struct net_device_ops plip_netdev_ops = {
+ .ndo_open = plip_open,
+ .ndo_stop = plip_close,
+ .ndo_start_xmit = plip_tx_packet,
+ .ndo_do_ioctl = plip_ioctl,
+};
+
/* Entry point of PLIP driver.
Probe the hardware, and register/initialize the driver.
@@ -280,15 +287,11 @@ plip_init_netdev(struct net_device *dev)
struct net_local *nl = netdev_priv(dev);
/* Then, override parts of it */
- dev->hard_start_xmit = plip_tx_packet;
- dev->open = plip_open;
- dev->stop = plip_close;
- dev->do_ioctl = plip_ioctl;
-
dev->tx_queue_len = 10;
dev->flags = IFF_POINTOPOINT|IFF_NOARP;
memset(dev->dev_addr, 0xfc, ETH_ALEN);
+ dev->netdev_ops = &plip_netdev_ops;
dev->header_ops = &plip_header_ops;
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 06b448285eb5..7b2728b8f1b7 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -250,6 +250,7 @@ static int ppp_connect_channel(struct channel *pch, int unit);
static int ppp_disconnect_channel(struct channel *pch);
static void ppp_destroy_channel(struct channel *pch);
static int unit_get(struct idr *p, void *ptr);
+static int unit_set(struct idr *p, void *ptr, int n);
static void unit_put(struct idr *p, int n);
static void *unit_find(struct idr *p, int n);
@@ -2432,11 +2433,18 @@ ppp_create_interface(int unit, int *retp)
} else {
if (unit_find(&ppp_units_idr, unit))
goto out2; /* unit already exists */
- else {
- /* darn, someone is cheating us? */
- *retp = -EINVAL;
+ /*
+ * if caller need a specified unit number
+ * lets try to satisfy him, otherwise --
+ * he should better ask us for new unit number
+ *
+ * NOTE: yes I know that returning EEXIST it's not
+ * fair but at least pppd will ask us to allocate
+ * new unit in this case so user is happy :)
+ */
+ unit = unit_set(&ppp_units_idr, ppp, unit);
+ if (unit < 0)
goto out2;
- }
}
/* Initialize the new ppp unit */
@@ -2677,14 +2685,37 @@ static void __exit ppp_cleanup(void)
* by holding all_ppp_mutex
*/
+/* associate pointer with specified number */
+static int unit_set(struct idr *p, void *ptr, int n)
+{
+ int unit, err;
+
+again:
+ if (!idr_pre_get(p, GFP_KERNEL)) {
+ printk(KERN_ERR "PPP: No free memory for idr\n");
+ return -ENOMEM;
+ }
+
+ err = idr_get_new_above(p, ptr, n, &unit);
+ if (err == -EAGAIN)
+ goto again;
+
+ if (unit != n) {
+ idr_remove(p, unit);
+ return -EINVAL;
+ }
+
+ return unit;
+}
+
/* get new free unit number and associate pointer with it */
static int unit_get(struct idr *p, void *ptr)
{
int unit, err;
again:
- if (idr_pre_get(p, GFP_KERNEL) == 0) {
- printk(KERN_ERR "Out of memory expanding drawable idr\n");
+ if (!idr_pre_get(p, GFP_KERNEL)) {
+ printk(KERN_ERR "PPP: No free memory for idr\n");
return -ENOMEM;
}
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 459663a4023d..c1dadadfab18 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -28,11 +28,11 @@
} while (0)
#define QLGE_VENDOR_ID 0x1077
-#define QLGE_DEVICE_ID1 0x8012
-#define QLGE_DEVICE_ID 0x8000
+#define QLGE_DEVICE_ID 0x8012
-#define MAX_RX_RINGS 128
-#define MAX_TX_RINGS 128
+#define MAX_CPUS 8
+#define MAX_TX_RINGS MAX_CPUS
+#define MAX_RX_RINGS ((MAX_CPUS * 2) + 1)
#define NUM_TX_RING_ENTRIES 256
#define NUM_RX_RING_ENTRIES 256
@@ -45,6 +45,7 @@
#define MAX_SPLIT_SIZE 1023
#define QLGE_SB_PAD 32
+#define MAX_CQ 128
#define DFLT_COALESCE_WAIT 100 /* 100 usec wait for coalescing */
#define MAX_INTER_FRAME_WAIT 10 /* 10 usec max interframe-wait for coalescing */
#define DFLT_INTER_FRAME_WAIT (MAX_INTER_FRAME_WAIT/2)
@@ -961,8 +962,7 @@ struct ib_mac_iocb_rsp {
#define IB_MAC_IOCB_RSP_DS 0x40 /* data is in small buffer */
#define IB_MAC_IOCB_RSP_DL 0x80 /* data is in large buffer */
__le32 data_len; /* */
- __le32 data_addr_lo; /* */
- __le32 data_addr_hi; /* */
+ __le64 data_addr; /* */
__le32 rss; /* */
__le16 vlan_id; /* 12 bits */
#define IB_MAC_IOCB_RSP_C 0x1000 /* VLAN CFI bit */
@@ -976,8 +976,7 @@ struct ib_mac_iocb_rsp {
#define IB_MAC_IOCB_RSP_HS 0x40
#define IB_MAC_IOCB_RSP_HL 0x80
__le32 hdr_len; /* */
- __le32 hdr_addr_lo; /* */
- __le32 hdr_addr_hi; /* */
+ __le64 hdr_addr; /* */
} __attribute((packed));
struct ib_ae_iocb_rsp {
@@ -1042,10 +1041,8 @@ struct wqicb {
__le16 cq_id_rss;
#define Q_CQ_ID_RSS_RV 0x8000
__le16 rid;
- __le32 addr_lo;
- __le32 addr_hi;
- __le32 cnsmr_idx_addr_lo;
- __le32 cnsmr_idx_addr_hi;
+ __le64 addr;
+ __le64 cnsmr_idx_addr;
} __attribute((packed));
/*
@@ -1070,18 +1067,14 @@ struct cqicb {
#define LEN_CPP_64 0x0002
#define LEN_CPP_128 0x0003
__le16 rid;
- __le32 addr_lo;
- __le32 addr_hi;
- __le32 prod_idx_addr_lo;
- __le32 prod_idx_addr_hi;
+ __le64 addr;
+ __le64 prod_idx_addr;
__le16 pkt_delay;
__le16 irq_delay;
- __le32 lbq_addr_lo;
- __le32 lbq_addr_hi;
+ __le64 lbq_addr;
__le16 lbq_buf_size;
__le16 lbq_len; /* entry count */
- __le32 sbq_addr_lo;
- __le32 sbq_addr_hi;
+ __le64 sbq_addr;
__le16 sbq_buf_size;
__le16 sbq_len; /* entry count */
} __attribute((packed));
@@ -1145,7 +1138,7 @@ struct tx_ring {
struct wqicb wqicb; /* structure used to inform chip of new queue */
void *wq_base; /* pci_alloc:virtual addr for tx */
dma_addr_t wq_base_dma; /* pci_alloc:dma addr for tx */
- u32 *cnsmr_idx_sh_reg; /* shadow copy of consumer idx */
+ __le32 *cnsmr_idx_sh_reg; /* shadow copy of consumer idx */
dma_addr_t cnsmr_idx_sh_reg_dma; /* dma-shadow copy of consumer */
u32 wq_size; /* size in bytes of queue area */
u32 wq_len; /* number of entries in queue */
@@ -1181,7 +1174,7 @@ struct rx_ring {
u32 cq_size;
u32 cq_len;
u16 cq_id;
- volatile __le32 *prod_idx_sh_reg; /* Shadowed producer register. */
+ __le32 *prod_idx_sh_reg; /* Shadowed producer register. */
dma_addr_t prod_idx_sh_reg_dma;
void __iomem *cnsmr_idx_db_reg; /* PCI doorbell mem area + 0 */
u32 cnsmr_idx; /* current sw idx */
@@ -1402,9 +1395,11 @@ struct ql_adapter {
int rx_ring_count;
int ring_mem_size;
void *ring_mem;
- struct rx_ring *rx_ring;
+
+ struct rx_ring rx_ring[MAX_RX_RINGS];
+ struct tx_ring tx_ring[MAX_TX_RINGS];
+
int rx_csum;
- struct tx_ring *tx_ring;
u32 default_rx_queue;
u16 rx_coalesce_usecs; /* cqicb->int_delay */
@@ -1459,6 +1454,24 @@ static inline void ql_write_db_reg(u32 val, void __iomem *addr)
mmiowb();
}
+/*
+ * Shadow Registers:
+ * Outbound queues have a consumer index that is maintained by the chip.
+ * Inbound queues have a producer index that is maintained by the chip.
+ * For lower overhead, these registers are "shadowed" to host memory
+ * which allows the device driver to track the queue progress without
+ * PCI reads. When an entry is placed on an inbound queue, the chip will
+ * update the relevant index register and then copy the value to the
+ * shadow register in host memory.
+ */
+static inline u32 ql_read_sh_reg(__le32 *addr)
+{
+ u32 reg;
+ reg = le32_to_cpu(*addr);
+ rmb();
+ return reg;
+}
+
extern char qlge_driver_name[];
extern const char qlge_driver_version[];
extern const struct ethtool_ops qlge_ethtool_ops;
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index 3f5e02d2e4a9..379b895ed6e6 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -435,14 +435,10 @@ void ql_dump_wqicb(struct wqicb *wqicb)
printk(KERN_ERR PFX "wqicb->cq_id_rss = %d.\n",
le16_to_cpu(wqicb->cq_id_rss));
printk(KERN_ERR PFX "wqicb->rid = 0x%x.\n", le16_to_cpu(wqicb->rid));
- printk(KERN_ERR PFX "wqicb->wq_addr_lo = 0x%.08x.\n",
- le32_to_cpu(wqicb->addr_lo));
- printk(KERN_ERR PFX "wqicb->wq_addr_hi = 0x%.08x.\n",
- le32_to_cpu(wqicb->addr_hi));
- printk(KERN_ERR PFX "wqicb->wq_cnsmr_idx_addr_lo = 0x%.08x.\n",
- le32_to_cpu(wqicb->cnsmr_idx_addr_lo));
- printk(KERN_ERR PFX "wqicb->wq_cnsmr_idx_addr_hi = 0x%.08x.\n",
- le32_to_cpu(wqicb->cnsmr_idx_addr_hi));
+ printk(KERN_ERR PFX "wqicb->wq_addr = 0x%llx.\n",
+ (unsigned long long) le64_to_cpu(wqicb->addr));
+ printk(KERN_ERR PFX "wqicb->wq_cnsmr_idx_addr = 0x%llx.\n",
+ (unsigned long long) le64_to_cpu(wqicb->cnsmr_idx_addr));
}
void ql_dump_tx_ring(struct tx_ring *tx_ring)
@@ -455,10 +451,11 @@ void ql_dump_tx_ring(struct tx_ring *tx_ring)
printk(KERN_ERR PFX "tx_ring->base = %p.\n", tx_ring->wq_base);
printk(KERN_ERR PFX "tx_ring->base_dma = 0x%llx.\n",
(unsigned long long) tx_ring->wq_base_dma);
- printk(KERN_ERR PFX "tx_ring->cnsmr_idx_sh_reg = %p.\n",
- tx_ring->cnsmr_idx_sh_reg);
- printk(KERN_ERR PFX "tx_ring->cnsmr_idx_sh_reg_dma = 0x%llx.\n",
- (unsigned long long) tx_ring->cnsmr_idx_sh_reg_dma);
+ printk(KERN_ERR PFX
+ "tx_ring->cnsmr_idx_sh_reg, addr = 0x%p, value = %d.\n",
+ tx_ring->cnsmr_idx_sh_reg,
+ tx_ring->cnsmr_idx_sh_reg
+ ? ql_read_sh_reg(tx_ring->cnsmr_idx_sh_reg) : 0);
printk(KERN_ERR PFX "tx_ring->size = %d.\n", tx_ring->wq_size);
printk(KERN_ERR PFX "tx_ring->len = %d.\n", tx_ring->wq_len);
printk(KERN_ERR PFX "tx_ring->prod_idx_db_reg = %p.\n",
@@ -510,30 +507,22 @@ void ql_dump_cqicb(struct cqicb *cqicb)
printk(KERN_ERR PFX "cqicb->msix_vect = %d.\n", cqicb->msix_vect);
printk(KERN_ERR PFX "cqicb->flags = %x.\n", cqicb->flags);
printk(KERN_ERR PFX "cqicb->len = %d.\n", le16_to_cpu(cqicb->len));
- printk(KERN_ERR PFX "cqicb->addr_lo = %x.\n",
- le32_to_cpu(cqicb->addr_lo));
- printk(KERN_ERR PFX "cqicb->addr_hi = %x.\n",
- le32_to_cpu(cqicb->addr_hi));
- printk(KERN_ERR PFX "cqicb->prod_idx_addr_lo = %x.\n",
- le32_to_cpu(cqicb->prod_idx_addr_lo));
- printk(KERN_ERR PFX "cqicb->prod_idx_addr_hi = %x.\n",
- le32_to_cpu(cqicb->prod_idx_addr_hi));
+ printk(KERN_ERR PFX "cqicb->addr = 0x%llx.\n",
+ (unsigned long long) le64_to_cpu(cqicb->addr));
+ printk(KERN_ERR PFX "cqicb->prod_idx_addr = 0x%llx.\n",
+ (unsigned long long) le64_to_cpu(cqicb->prod_idx_addr));
printk(KERN_ERR PFX "cqicb->pkt_delay = 0x%.04x.\n",
le16_to_cpu(cqicb->pkt_delay));
printk(KERN_ERR PFX "cqicb->irq_delay = 0x%.04x.\n",
le16_to_cpu(cqicb->irq_delay));
- printk(KERN_ERR PFX "cqicb->lbq_addr_lo = %x.\n",
- le32_to_cpu(cqicb->lbq_addr_lo));
- printk(KERN_ERR PFX "cqicb->lbq_addr_hi = %x.\n",
- le32_to_cpu(cqicb->lbq_addr_hi));
+ printk(KERN_ERR PFX "cqicb->lbq_addr = 0x%llx.\n",
+ (unsigned long long) le64_to_cpu(cqicb->lbq_addr));
printk(KERN_ERR PFX "cqicb->lbq_buf_size = 0x%.04x.\n",
le16_to_cpu(cqicb->lbq_buf_size));
printk(KERN_ERR PFX "cqicb->lbq_len = 0x%.04x.\n",
le16_to_cpu(cqicb->lbq_len));
- printk(KERN_ERR PFX "cqicb->sbq_addr_lo = %x.\n",
- le32_to_cpu(cqicb->sbq_addr_lo));
- printk(KERN_ERR PFX "cqicb->sbq_addr_hi = %x.\n",
- le32_to_cpu(cqicb->sbq_addr_hi));
+ printk(KERN_ERR PFX "cqicb->sbq_addr = 0x%llx.\n",
+ (unsigned long long) le64_to_cpu(cqicb->sbq_addr));
printk(KERN_ERR PFX "cqicb->sbq_buf_size = 0x%.04x.\n",
le16_to_cpu(cqicb->sbq_buf_size));
printk(KERN_ERR PFX "cqicb->sbq_len = 0x%.04x.\n",
@@ -558,9 +547,10 @@ void ql_dump_rx_ring(struct rx_ring *rx_ring)
printk(KERN_ERR PFX "rx_ring->cq_size = %d.\n", rx_ring->cq_size);
printk(KERN_ERR PFX "rx_ring->cq_len = %d.\n", rx_ring->cq_len);
printk(KERN_ERR PFX
- "rx_ring->prod_idx_sh_reg, addr = %p, value = %d.\n",
+ "rx_ring->prod_idx_sh_reg, addr = 0x%p, value = %d.\n",
rx_ring->prod_idx_sh_reg,
- rx_ring->prod_idx_sh_reg ? *(rx_ring->prod_idx_sh_reg) : 0);
+ rx_ring->prod_idx_sh_reg
+ ? ql_read_sh_reg(rx_ring->prod_idx_sh_reg) : 0);
printk(KERN_ERR PFX "rx_ring->prod_idx_sh_reg_dma = %llx.\n",
(unsigned long long) rx_ring->prod_idx_sh_reg_dma);
printk(KERN_ERR PFX "rx_ring->cnsmr_idx_db_reg = %p.\n",
@@ -809,10 +799,8 @@ void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp)
printk(KERN_ERR PFX "data_len = %d\n",
le32_to_cpu(ib_mac_rsp->data_len));
- printk(KERN_ERR PFX "data_addr_hi = 0x%x\n",
- le32_to_cpu(ib_mac_rsp->data_addr_hi));
- printk(KERN_ERR PFX "data_addr_lo = 0x%x\n",
- le32_to_cpu(ib_mac_rsp->data_addr_lo));
+ printk(KERN_ERR PFX "data_addr = 0x%llx\n",
+ (unsigned long long) le64_to_cpu(ib_mac_rsp->data_addr));
if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK)
printk(KERN_ERR PFX "rss = %x\n",
le32_to_cpu(ib_mac_rsp->rss));
@@ -828,10 +816,8 @@ void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp)
if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV) {
printk(KERN_ERR PFX "hdr length = %d.\n",
le32_to_cpu(ib_mac_rsp->hdr_len));
- printk(KERN_ERR PFX "hdr addr_hi = 0x%x.\n",
- le32_to_cpu(ib_mac_rsp->hdr_addr_hi));
- printk(KERN_ERR PFX "hdr addr_lo = 0x%x.\n",
- le32_to_cpu(ib_mac_rsp->hdr_addr_lo));
+ printk(KERN_ERR PFX "hdr addr = 0x%llx.\n",
+ (unsigned long long) le64_to_cpu(ib_mac_rsp->hdr_addr));
}
}
#endif
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index f4c016012f18..45421c8b6010 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -76,7 +76,6 @@ MODULE_PARM_DESC(irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy.");
static struct pci_device_id qlge_pci_tbl[] __devinitdata = {
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID)},
- {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID1)},
/* required last entry */
{0,}
};
@@ -127,12 +126,12 @@ static int ql_sem_trylock(struct ql_adapter *qdev, u32 sem_mask)
int ql_sem_spinlock(struct ql_adapter *qdev, u32 sem_mask)
{
- unsigned int seconds = 3;
+ unsigned int wait_count = 30;
do {
if (!ql_sem_trylock(qdev, sem_mask))
return 0;
- ssleep(1);
- } while (--seconds);
+ udelay(100);
+ } while (--wait_count);
return -ETIMEDOUT;
}
@@ -1545,7 +1544,7 @@ static void ql_process_chip_ae_intr(struct ql_adapter *qdev,
static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring)
{
struct ql_adapter *qdev = rx_ring->qdev;
- u32 prod = le32_to_cpu(*rx_ring->prod_idx_sh_reg);
+ u32 prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
struct ob_mac_iocb_rsp *net_rsp = NULL;
int count = 0;
@@ -1571,7 +1570,7 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring)
}
count++;
ql_update_cq(rx_ring);
- prod = le32_to_cpu(*rx_ring->prod_idx_sh_reg);
+ prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
}
ql_write_cq_idx(rx_ring);
if (netif_queue_stopped(qdev->ndev) && net_rsp != NULL) {
@@ -1591,7 +1590,7 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring)
static int ql_clean_inbound_rx_ring(struct rx_ring *rx_ring, int budget)
{
struct ql_adapter *qdev = rx_ring->qdev;
- u32 prod = le32_to_cpu(*rx_ring->prod_idx_sh_reg);
+ u32 prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
struct ql_net_rsp_iocb *net_rsp;
int count = 0;
@@ -1624,7 +1623,7 @@ static int ql_clean_inbound_rx_ring(struct rx_ring *rx_ring, int budget)
}
count++;
ql_update_cq(rx_ring);
- prod = le32_to_cpu(*rx_ring->prod_idx_sh_reg);
+ prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
if (count == budget)
break;
}
@@ -1787,7 +1786,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
* Check the default queue and wake handler if active.
*/
rx_ring = &qdev->rx_ring[0];
- if (le32_to_cpu(*rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) {
+ if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) {
QPRINTK(qdev, INTR, INFO, "Waking handler for rx_ring[0].\n");
ql_disable_completion_interrupt(qdev, intr_context->intr);
queue_delayed_work_on(smp_processor_id(), qdev->q_workqueue,
@@ -1801,7 +1800,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
*/
for (i = 1; i < qdev->rx_ring_count; i++) {
rx_ring = &qdev->rx_ring[i];
- if (le32_to_cpu(*rx_ring->prod_idx_sh_reg) !=
+ if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) !=
rx_ring->cnsmr_idx) {
QPRINTK(qdev, INTR, INFO,
"Waking handler for rx_ring[%d].\n", i);
@@ -2356,28 +2355,6 @@ static void ql_tx_ring_clean(struct ql_adapter *qdev)
}
}
-static void ql_free_ring_cb(struct ql_adapter *qdev)
-{
- kfree(qdev->ring_mem);
-}
-
-static int ql_alloc_ring_cb(struct ql_adapter *qdev)
-{
- /* Allocate space for tx/rx ring control blocks. */
- qdev->ring_mem_size =
- (qdev->tx_ring_count * sizeof(struct tx_ring)) +
- (qdev->rx_ring_count * sizeof(struct rx_ring));
- qdev->ring_mem = kmalloc(qdev->ring_mem_size, GFP_KERNEL);
- if (qdev->ring_mem == NULL) {
- return -ENOMEM;
- } else {
- qdev->rx_ring = qdev->ring_mem;
- qdev->tx_ring = qdev->ring_mem +
- (qdev->rx_ring_count * sizeof(struct rx_ring));
- }
- return 0;
-}
-
static void ql_free_mem_resources(struct ql_adapter *qdev)
{
int i;
@@ -2467,12 +2444,9 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
bq_len = (rx_ring->cq_len == 65536) ? 0 : (u16) rx_ring->cq_len;
cqicb->len = cpu_to_le16(bq_len | LEN_V | LEN_CPP_CONT);
- cqicb->addr_lo = cpu_to_le32(rx_ring->cq_base_dma);
- cqicb->addr_hi = cpu_to_le32((u64) rx_ring->cq_base_dma >> 32);
+ cqicb->addr = cpu_to_le64(rx_ring->cq_base_dma);
- cqicb->prod_idx_addr_lo = cpu_to_le32(rx_ring->prod_idx_sh_reg_dma);
- cqicb->prod_idx_addr_hi =
- cpu_to_le32((u64) rx_ring->prod_idx_sh_reg_dma >> 32);
+ cqicb->prod_idx_addr = cpu_to_le64(rx_ring->prod_idx_sh_reg_dma);
/*
* Set up the control block load flags.
@@ -2483,10 +2457,8 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
if (rx_ring->lbq_len) {
cqicb->flags |= FLAGS_LL; /* Load lbq values */
*((u64 *) rx_ring->lbq_base_indirect) = rx_ring->lbq_base_dma;
- cqicb->lbq_addr_lo =
- cpu_to_le32(rx_ring->lbq_base_indirect_dma);
- cqicb->lbq_addr_hi =
- cpu_to_le32((u64) rx_ring->lbq_base_indirect_dma >> 32);
+ cqicb->lbq_addr =
+ cpu_to_le64(rx_ring->lbq_base_indirect_dma);
bq_len = (rx_ring->lbq_buf_size == 65536) ? 0 :
(u16) rx_ring->lbq_buf_size;
cqicb->lbq_buf_size = cpu_to_le16(bq_len);
@@ -2501,10 +2473,8 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
if (rx_ring->sbq_len) {
cqicb->flags |= FLAGS_LS; /* Load sbq values */
*((u64 *) rx_ring->sbq_base_indirect) = rx_ring->sbq_base_dma;
- cqicb->sbq_addr_lo =
- cpu_to_le32(rx_ring->sbq_base_indirect_dma);
- cqicb->sbq_addr_hi =
- cpu_to_le32((u64) rx_ring->sbq_base_indirect_dma >> 32);
+ cqicb->sbq_addr =
+ cpu_to_le64(rx_ring->sbq_base_indirect_dma);
cqicb->sbq_buf_size =
cpu_to_le16(((rx_ring->sbq_buf_size / 2) + 8) & 0xfffffff8);
bq_len = (rx_ring->sbq_len == 65536) ? 0 :
@@ -2611,12 +2581,9 @@ static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring)
Q_FLAGS_LB | Q_FLAGS_LI | Q_FLAGS_LO);
wqicb->cq_id_rss = cpu_to_le16(tx_ring->cq_id);
wqicb->rid = 0;
- wqicb->addr_lo = cpu_to_le32(tx_ring->wq_base_dma);
- wqicb->addr_hi = cpu_to_le32((u64) tx_ring->wq_base_dma >> 32);
+ wqicb->addr = cpu_to_le64(tx_ring->wq_base_dma);
- wqicb->cnsmr_idx_addr_lo = cpu_to_le32(tx_ring->cnsmr_idx_sh_reg_dma);
- wqicb->cnsmr_idx_addr_hi =
- cpu_to_le32((u64) tx_ring->cnsmr_idx_sh_reg_dma >> 32);
+ wqicb->cnsmr_idx_addr = cpu_to_le64(tx_ring->cnsmr_idx_sh_reg_dma);
ql_init_tx_ring(qdev, tx_ring);
@@ -2746,14 +2713,14 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev)
* Outbound queue is for outbound completions only.
*/
intr_context->handler = qlge_msix_tx_isr;
- sprintf(intr_context->name, "%s-txq-%d",
+ sprintf(intr_context->name, "%s-tx-%d",
qdev->ndev->name, i);
} else {
/*
* Inbound queues handle unicast frames only.
*/
intr_context->handler = qlge_msix_rx_isr;
- sprintf(intr_context->name, "%s-rxq-%d",
+ sprintf(intr_context->name, "%s-rx-%d",
qdev->ndev->name, i);
}
}
@@ -3247,7 +3214,6 @@ static int qlge_close(struct net_device *ndev)
msleep(1);
ql_adapter_down(qdev);
ql_release_adapter_resources(qdev);
- ql_free_ring_cb(qdev);
return 0;
}
@@ -3273,8 +3239,8 @@ static int ql_configure_rings(struct ql_adapter *qdev)
* This limitation can be removed when requested.
*/
- if (cpu_cnt > 8)
- cpu_cnt = 8;
+ if (cpu_cnt > MAX_CPUS)
+ cpu_cnt = MAX_CPUS;
/*
* rx_ring[0] is always the default queue.
@@ -3294,9 +3260,6 @@ static int ql_configure_rings(struct ql_adapter *qdev)
*/
qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1;
- if (ql_alloc_ring_cb(qdev))
- return -ENOMEM;
-
for (i = 0; i < qdev->tx_ring_count; i++) {
tx_ring = &qdev->tx_ring[i];
memset((void *)tx_ring, 0, sizeof(tx_ring));
@@ -3393,7 +3356,6 @@ static int qlge_open(struct net_device *ndev)
error_up:
ql_release_adapter_resources(qdev);
- ql_free_ring_cb(qdev);
return err;
}
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 53bbddfc8c95..72fd9e97c190 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -49,8 +49,8 @@
#include <asm/processor.h>
#define DRV_NAME "r6040"
-#define DRV_VERSION "0.19"
-#define DRV_RELDATE "18Dec2008"
+#define DRV_VERSION "0.21"
+#define DRV_RELDATE "09Jan2009"
/* PHY CHIP Address */
#define PHY1_ADDR 1 /* For MAC1 */
@@ -200,7 +200,7 @@ struct r6040_private {
static char version[] __devinitdata = KERN_INFO DRV_NAME
": RDC R6040 NAPI net driver,"
- "version "DRV_VERSION " (" DRV_RELDATE ")\n";
+ "version "DRV_VERSION " (" DRV_RELDATE ")";
static int phy_table[] = { PHY1_ADDR, PHY2_ADDR };
@@ -330,7 +330,7 @@ static int r6040_alloc_rxbufs(struct net_device *dev)
do {
skb = netdev_alloc_skb(dev, MAX_BUF_SIZE);
if (!skb) {
- printk(KERN_ERR "%s: failed to alloc skb for rx\n", dev->name);
+ printk(KERN_ERR DRV_NAME "%s: failed to alloc skb for rx\n", dev->name);
rc = -ENOMEM;
goto err_exit;
}
@@ -457,22 +457,12 @@ static void r6040_down(struct net_device *dev)
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 */
- r6040_free_rxbufs(dev);
-
- /* Free TX buffer */
- r6040_free_txbufs(dev);
-
- /* 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);
+ struct pci_dev *pdev = lp->pdev;
/* deleted timer */
del_timer_sync(&lp->timer);
@@ -481,8 +471,28 @@ static int r6040_close(struct net_device *dev)
napi_disable(&lp->napi);
netif_stop_queue(dev);
r6040_down(dev);
+
+ free_irq(dev->irq, dev);
+
+ /* Free RX buffer */
+ r6040_free_rxbufs(dev);
+
+ /* Free TX buffer */
+ r6040_free_txbufs(dev);
+
spin_unlock_irq(&lp->lock);
+ /* Free Descriptor memory */
+ if (lp->rx_ring) {
+ pci_free_consistent(pdev, RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma);
+ lp->rx_ring = 0;
+ }
+
+ if (lp->tx_ring) {
+ pci_free_consistent(pdev, TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma);
+ lp->tx_ring = 0;
+ }
+
return 0;
}
@@ -1049,6 +1059,7 @@ static const struct net_device_ops r6040_netdev_ops = {
.ndo_set_multicast_list = r6040_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_do_ioctl = r6040_ioctl,
.ndo_tx_timeout = r6040_tx_timeout,
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1077,20 +1088,20 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
/* this should always be supported */
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
- printk(KERN_ERR DRV_NAME "32-bit PCI DMA addresses"
+ printk(KERN_ERR DRV_NAME ": 32-bit PCI DMA addresses"
"not supported by the card\n");
goto err_out;
}
err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
- printk(KERN_ERR DRV_NAME "32-bit PCI DMA addresses"
+ printk(KERN_ERR DRV_NAME ": 32-bit PCI DMA addresses"
"not supported by the card\n");
goto err_out;
}
/* IO Size check */
if (pci_resource_len(pdev, 0) < io_size) {
- printk(KERN_ERR DRV_NAME "Insufficient PCI resources, aborting\n");
+ printk(KERN_ERR DRV_NAME ": Insufficient PCI resources, aborting\n");
err = -EIO;
goto err_out;
}
@@ -1100,7 +1111,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(struct r6040_private));
if (!dev) {
- printk(KERN_ERR DRV_NAME "Failed to allocate etherdev\n");
+ printk(KERN_ERR DRV_NAME ": Failed to allocate etherdev\n");
err = -ENOMEM;
goto err_out;
}
@@ -1116,11 +1127,15 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
ioaddr = pci_iomap(pdev, bar, io_size);
if (!ioaddr) {
- printk(KERN_ERR "ioremap failed for device %s\n",
+ printk(KERN_ERR DRV_NAME ": ioremap failed for device %s\n",
pci_name(pdev));
err = -EIO;
goto err_out_free_res;
}
+ /* If PHY status change register is still set to zero it means the
+ * bootloader didn't initialize it */
+ if (ioread16(ioaddr + PHY_CC) == 0)
+ iowrite16(0x9f07, ioaddr + PHY_CC);
/* Init system & device */
lp->base = ioaddr;
@@ -1137,6 +1152,13 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
adrp[1] = ioread16(ioaddr + MID_0M);
adrp[2] = ioread16(ioaddr + MID_0H);
+ /* Some bootloader/BIOSes do not initialize
+ * MAC address, warn about that */
+ if (!(adrp[0] || adrp[1] || adrp[2])) {
+ printk(KERN_WARNING DRV_NAME ": MAC address not initialized, generating random\n");
+ random_ether_addr(dev->dev_addr);
+ }
+
/* Link new device into r6040_root_dev */
lp->pdev = pdev;
lp->dev = dev;
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index be3025310e90..fc0e38bddeeb 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -134,6 +134,16 @@ static const struct pnp_device_id sb1000_pnp_ids[] = {
};
MODULE_DEVICE_TABLE(pnp, sb1000_pnp_ids);
+static const struct net_device_ops sb1000_netdev_ops = {
+ .ndo_open = sb1000_open,
+ .ndo_start_xmit = sb1000_start_xmit,
+ .ndo_do_ioctl = sb1000_dev_ioctl,
+ .ndo_stop = sb1000_close,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
static int
sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id)
{
@@ -192,11 +202,7 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id)
if (sb1000_debug > 0)
printk(KERN_NOTICE "%s", version);
- /* The SB1000-specific entries in the device structure. */
- dev->open = sb1000_open;
- dev->do_ioctl = sb1000_dev_ioctl;
- dev->hard_start_xmit = sb1000_start_xmit;
- dev->stop = sb1000_close;
+ dev->netdev_ops = &sb1000_netdev_ops;
/* hardware address is 0:0:serial_number */
dev->dev_addr[2] = serial_number >> 24 & 0xff;
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
index 42fd31276602..8b75bef4a841 100644
--- a/drivers/net/sc92031.c
+++ b/drivers/net/sc92031.c
@@ -1408,6 +1408,7 @@ static const struct net_device_ops sc92031_netdev_ops = {
.ndo_set_multicast_list = sc92031_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_tx_timeout = sc92031_tx_timeout,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = sc92031_poll_controller,
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 6884dc8c1f82..5b9f2d9cc4ed 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1403,9 +1403,9 @@ static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
}
/* Disable both devices */
- pci_disable_device(efx->pci_dev);
+ pci_clear_master(efx->pci_dev);
if (FALCON_IS_DUAL_FUNC(efx))
- pci_disable_device(nic_data->pci_dev2);
+ pci_clear_master(nic_data->pci_dev2);
falcon_disable_interrupts(efx);
if (++n_int_errors < FALCON_MAX_INT_ERRORS) {
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index b9768760fae7..9ecb77da9545 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -636,10 +636,11 @@ static void tenxpress_phy_fini(struct efx_nic *efx)
{
int reg;
- if (efx->phy_type == PHY_TYPE_SFT9001B) {
+ if (efx->phy_type == PHY_TYPE_SFT9001B)
device_remove_file(&efx->pci_dev->dev,
&dev_attr_phy_short_reach);
- } else {
+
+ if (efx->phy_type == PHY_TYPE_SFX7101) {
/* Power down the LNPGA */
reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 83cc3c5f7946..a9732686134b 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -1782,6 +1782,21 @@ static int sis190_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
generic_mii_ioctl(&tp->mii_if, if_mii(ifr), cmd, NULL);
}
+static const struct net_device_ops sis190_netdev_ops = {
+ .ndo_open = sis190_open,
+ .ndo_stop = sis190_close,
+ .ndo_do_ioctl = sis190_ioctl,
+ .ndo_start_xmit = sis190_start_xmit,
+ .ndo_tx_timeout = sis190_tx_timeout,
+ .ndo_set_multicast_list = sis190_set_rx_mode,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = sis190_netpoll,
+#endif
+};
+
static int __devinit sis190_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -1815,19 +1830,12 @@ static int __devinit sis190_init_one(struct pci_dev *pdev,
INIT_WORK(&tp->phy_task, sis190_phy_task);
- dev->open = sis190_open;
- dev->stop = sis190_close;
- dev->do_ioctl = sis190_ioctl;
- dev->tx_timeout = sis190_tx_timeout;
- dev->watchdog_timeo = SIS190_TX_TIMEOUT;
- dev->hard_start_xmit = sis190_start_xmit;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = sis190_netpoll;
-#endif
- dev->set_multicast_list = sis190_set_rx_mode;
+ dev->netdev_ops = &sis190_netdev_ops;
+
SET_ETHTOOL_OPS(dev, &sis190_ethtool_ops);
dev->irq = pdev->irq;
dev->base_addr = (unsigned long) 0xdead;
+ dev->watchdog_timeo = SIS190_TX_TIMEOUT;
spin_lock_init(&tp->lock);
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 4acd41a093ad..be4465bc0a69 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -389,6 +389,7 @@ static const struct net_device_ops sis900_netdev_ops = {
.ndo_set_multicast_list = set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_do_ioctl = mii_ioctl,
.ndo_tx_timeout = sis900_tx_timeout,
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -508,10 +509,10 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
else
ret = sis900_get_mac_addr(pci_dev, net_dev);
- if (ret == 0) {
- printk(KERN_WARNING "%s: Cannot read MAC address.\n", dev_name);
- ret = -ENODEV;
- goto err_unmap_rx;
+ if (!ret || !is_valid_ether_addr(net_dev->dev_addr)) {
+ random_ether_addr(net_dev->dev_addr);
+ printk(KERN_WARNING "%s: Unreadable or invalid MAC address,"
+ "using random generated one\n", dev_name);
}
/* 630ET : set the mii access mode as software-mode */
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 8e1c0baf6958..5c61d5fad908 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -603,7 +603,6 @@ static int sl_init(struct net_device *dev)
dev->mtu = sl->mtu;
dev->type = ARPHRD_SLIP + sl->mode;
#ifdef SL_CHECK_TRANSMIT
- dev->tx_timeout = sl_tx_timeout;
dev->watchdog_timeo = 20*HZ;
#endif
return 0;
@@ -617,19 +616,26 @@ static void sl_uninit(struct net_device *dev)
sl_free_bufs(sl);
}
+static const struct net_device_ops sl_netdev_ops = {
+ .ndo_init = sl_init,
+ .ndo_uninit = sl_uninit,
+ .ndo_open = sl_open,
+ .ndo_stop = sl_close,
+ .ndo_start_xmit = sl_xmit,
+ .ndo_get_stats = sl_get_stats,
+ .ndo_change_mtu = sl_change_mtu,
+ .ndo_tx_timeout = sl_tx_timeout,
+#ifdef CONFIG_SLIP_SMART
+ .ndo_do_ioctl = sl_ioctl,
+#endif
+};
+
+
static void sl_setup(struct net_device *dev)
{
- dev->init = sl_init;
- dev->uninit = sl_uninit;
- dev->open = sl_open;
+ dev->netdev_ops = &sl_netdev_ops;
dev->destructor = free_netdev;
- dev->stop = sl_close;
- dev->get_stats = sl_get_stats;
- dev->change_mtu = sl_change_mtu;
- dev->hard_start_xmit = sl_xmit;
-#ifdef CONFIG_SLIP_SMART
- dev->do_ioctl = sl_ioctl;
-#endif
+
dev->hard_header_len = 0;
dev->addr_len = 0;
dev->tx_queue_len = 10;
diff --git a/drivers/net/slip.h b/drivers/net/slip.h
index 853e0f6ec710..9ea5c11287d2 100644
--- a/drivers/net/slip.h
+++ b/drivers/net/slip.h
@@ -75,7 +75,7 @@ struct slip {
unsigned long tx_errors; /* Planned stuff */
unsigned long rx_dropped; /* No memory for skb */
unsigned long tx_dropped; /* When MTU change */
- unsigned long rx_over_errors; /* Frame bigger then SLIP buf. */
+ unsigned long rx_over_errors; /* Frame bigger than SLIP buf. */
#ifdef SL_INCLUDE_CSLIP
unsigned long tx_compressed;
unsigned long rx_compressed;
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index 404b80e5ba11..8d36d40649ef 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -192,6 +192,7 @@ static const struct net_device_ops ultramca_netdev_ops = {
.ndo_get_stats = ei_get_stats,
.ndo_set_multicast_list = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ei_poll,
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index b3866089a206..2033fee3143a 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -196,6 +196,7 @@ static const struct net_device_ops ultra_netdev_ops = {
.ndo_get_stats = ei_get_stats,
.ndo_set_multicast_list = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ei_poll,
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index dc3f1108884d..f513bdf1c887 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -144,6 +144,7 @@ static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
}
BUG();
+ return 0;
}
static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
@@ -1740,6 +1741,7 @@ static const struct net_device_ops smsc911x_netdev_ops = {
.ndo_set_multicast_list = smsc911x_set_multicast_list,
.ndo_do_ioctl = smsc911x_do_ioctl,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = smsc911x_poll_controller,
#endif
@@ -1967,7 +1969,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
retval = request_irq(dev->irq, smsc911x_irqhandler, IRQF_DISABLED,
- SMSC_CHIPNAME, dev);
+ dev->name, dev);
if (retval) {
SMSC_WARNING(PROBE,
"Unable to claim requested irq: %d", dev->irq);
diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c
index 27e017d96966..c14a4c6452c7 100644
--- a/drivers/net/smsc9420.c
+++ b/drivers/net/smsc9420.c
@@ -1551,6 +1551,7 @@ static const struct net_device_ops smsc9420_netdev_ops = {
.ndo_set_multicast_list = smsc9420_set_multicast_list,
.ndo_do_ioctl = smsc9420_do_ioctl,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = smsc9420_poll_controller,
#endif /* CONFIG_NET_POLL_CONTROLLER */
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 57fb1f71c47b..da3a76b18eff 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -648,6 +648,24 @@ static void netdev_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
#endif /* VLAN_SUPPORT */
+static const struct net_device_ops netdev_ops = {
+ .ndo_open = netdev_open,
+ .ndo_stop = netdev_close,
+ .ndo_start_xmit = start_tx,
+ .ndo_tx_timeout = tx_timeout,
+ .ndo_get_stats = get_stats,
+ .ndo_set_multicast_list = &set_rx_mode,
+ .ndo_do_ioctl = netdev_ioctl,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef VLAN_SUPPORT
+ .ndo_vlan_rx_register = netdev_vlan_rx_register,
+ .ndo_vlan_rx_add_vid = netdev_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = netdev_vlan_rx_kill_vid,
+#endif
+};
+
static int __devinit starfire_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -710,11 +728,9 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
if (enable_hw_cksum)
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
#endif /* ZEROCOPY */
+
#ifdef VLAN_SUPPORT
dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
- dev->vlan_rx_register = netdev_vlan_rx_register;
- dev->vlan_rx_add_vid = netdev_vlan_rx_add_vid;
- dev->vlan_rx_kill_vid = netdev_vlan_rx_kill_vid;
#endif /* VLAN_RX_KILL_VID */
#ifdef ADDR_64BITS
dev->features |= NETIF_F_HIGHDMA;
@@ -810,18 +826,12 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
}
}
- /* The chip-specific entries in the device structure. */
- dev->open = &netdev_open;
- dev->hard_start_xmit = &start_tx;
- dev->tx_timeout = tx_timeout;
+ dev->netdev_ops = &netdev_ops;
dev->watchdog_timeo = TX_TIMEOUT;
- netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work);
- dev->stop = &netdev_close;
- dev->get_stats = &get_stats;
- dev->set_multicast_list = &set_rx_mode;
- dev->do_ioctl = &netdev_ioctl;
SET_ETHTOOL_OPS(dev, &ethtool_ops);
+ netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work);
+
if (mtu)
dev->mtu = mtu;
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 698893b92003..feaf0e0577d7 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -449,6 +449,19 @@ static void sundance_reset(struct net_device *dev, unsigned long reset_cmd)
}
}
+static const struct net_device_ops netdev_ops = {
+ .ndo_open = netdev_open,
+ .ndo_stop = netdev_close,
+ .ndo_start_xmit = start_tx,
+ .ndo_get_stats = get_stats,
+ .ndo_set_multicast_list = set_rx_mode,
+ .ndo_do_ioctl = netdev_ioctl,
+ .ndo_tx_timeout = tx_timeout,
+ .ndo_change_mtu = change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
static int __devinit sundance_probe1 (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -530,16 +543,10 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
np->mii_if.reg_num_mask = 0x1f;
/* The chip-specific entries in the device structure. */
- dev->open = &netdev_open;
- dev->hard_start_xmit = &start_tx;
- dev->stop = &netdev_close;
- dev->get_stats = &get_stats;
- dev->set_multicast_list = &set_rx_mode;
- dev->do_ioctl = &netdev_ioctl;
+ dev->netdev_ops = &netdev_ops;
SET_ETHTOOL_OPS(dev, &ethtool_ops);
- dev->tx_timeout = &tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
- dev->change_mtu = &change_mtu;
+
pci_set_drvdata(pdev, dev);
i = register_netdev(dev);
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 8a7460412482..86c765d83de1 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -2989,6 +2989,19 @@ static void gem_remove_one(struct pci_dev *pdev)
}
}
+static const struct net_device_ops gem_netdev_ops = {
+ .ndo_open = gem_open,
+ .ndo_stop = gem_close,
+ .ndo_start_xmit = gem_start_xmit,
+ .ndo_get_stats = gem_get_stats,
+ .ndo_set_multicast_list = gem_set_multicast,
+ .ndo_do_ioctl = gem_ioctl,
+ .ndo_tx_timeout = gem_tx_timeout,
+ .ndo_change_mtu = gem_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
static int __devinit gem_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -3142,17 +3155,10 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
if (gem_get_device_address(gp))
goto err_out_free_consistent;
- dev->open = gem_open;
- dev->stop = gem_close;
- dev->hard_start_xmit = gem_start_xmit;
- dev->get_stats = gem_get_stats;
- dev->set_multicast_list = gem_set_multicast;
- dev->do_ioctl = gem_ioctl;
+ dev->netdev_ops = &gem_netdev_ops;
netif_napi_add(dev, &gp->napi, gem_poll, 64);
dev->ethtool_ops = &gem_ethtool_ops;
- dev->tx_timeout = gem_tx_timeout;
dev->watchdog_timeo = 5 * HZ;
- dev->change_mtu = gem_change_mtu;
dev->irq = pdev->irq;
dev->dma = 0;
dev->set_mac_address = gem_set_mac_address;
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index b22d3355fb45..7a72a3112f0a 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -2607,6 +2607,18 @@ static struct quattro * __devinit quattro_pci_find(struct pci_dev *pdev)
}
#endif /* CONFIG_PCI */
+static const struct net_device_ops hme_netdev_ops = {
+ .ndo_open = happy_meal_open,
+ .ndo_stop = happy_meal_close,
+ .ndo_start_xmit = happy_meal_start_xmit,
+ .ndo_tx_timeout = happy_meal_tx_timeout,
+ .ndo_get_stats = happy_meal_get_stats,
+ .ndo_set_multicast_list = happy_meal_set_multicast,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
#ifdef CONFIG_SBUS
static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe)
{
@@ -2750,12 +2762,7 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe)
init_timer(&hp->happy_timer);
hp->dev = dev;
- dev->open = &happy_meal_open;
- dev->stop = &happy_meal_close;
- dev->hard_start_xmit = &happy_meal_start_xmit;
- dev->get_stats = &happy_meal_get_stats;
- dev->set_multicast_list = &happy_meal_set_multicast;
- dev->tx_timeout = &happy_meal_tx_timeout;
+ dev->netdev_ops = &hme_netdev_ops;
dev->watchdog_timeo = 5*HZ;
dev->ethtool_ops = &hme_ethtool_ops;
@@ -3076,12 +3083,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
init_timer(&hp->happy_timer);
hp->dev = dev;
- dev->open = &happy_meal_open;
- dev->stop = &happy_meal_close;
- dev->hard_start_xmit = &happy_meal_start_xmit;
- dev->get_stats = &happy_meal_get_stats;
- dev->set_multicast_list = &happy_meal_set_multicast;
- dev->tx_timeout = &happy_meal_tx_timeout;
+ dev->netdev_ops = &hme_netdev_ops;
dev->watchdog_timeo = 5*HZ;
dev->ethtool_ops = &hme_ethtool_ops;
dev->irq = pdev->irq;
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index 233f1cda36e5..611230fef2b6 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -336,7 +336,7 @@ static int vnet_walk_rx_one(struct vnet_port *port,
if (IS_ERR(desc))
return PTR_ERR(desc);
- viodbg(DATA, "vio_walk_rx_one desc[%02x:%02x:%08x:%08x:%lx:%lx]\n",
+ viodbg(DATA, "vio_walk_rx_one desc[%02x:%02x:%08x:%08x:%llx:%llx]\n",
desc->hdr.state, desc->hdr.ack,
desc->size, desc->ncookies,
desc->cookies[0].cookie_addr,
@@ -394,14 +394,14 @@ static int vnet_rx(struct vnet_port *port, void *msgbuf)
struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_RX_RING];
struct vio_driver_state *vio = &port->vio;
- viodbg(DATA, "vnet_rx stype_env[%04x] seq[%016lx] rcv_nxt[%016lx]\n",
+ viodbg(DATA, "vnet_rx stype_env[%04x] seq[%016llx] rcv_nxt[%016llx]\n",
pkt->tag.stype_env, pkt->seq, dr->rcv_nxt);
if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA))
return 0;
if (unlikely(pkt->seq != dr->rcv_nxt)) {
- printk(KERN_ERR PFX "RX out of sequence seq[0x%lx] "
- "rcv_nxt[0x%lx]\n", pkt->seq, dr->rcv_nxt);
+ printk(KERN_ERR PFX "RX out of sequence seq[0x%llx] "
+ "rcv_nxt[0x%llx]\n", pkt->seq, dr->rcv_nxt);
return 0;
}
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index a10a83a11d9f..a7a4dc4d6313 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -1004,7 +1004,7 @@ static inline void bdx_rxdb_free_elem(struct rxdb *db, int n)
* skb for rx. It assumes that Rx is desabled in HW
* funcs are grouped for better cache usage
*
- * RxD fifo is smaller then RxF fifo by design. Upon high load, RxD will be
+ * RxD fifo is smaller than RxF fifo by design. Upon high load, RxD will be
* filled and packets will be dropped by nic without getting into host or
* cousing interrupt. Anyway, in that condition, host has no chance to proccess
* all packets, but dropping in nic is cheaper, since it takes 0 cpu cycles
@@ -1826,7 +1826,7 @@ static void bdx_tx_free(struct bdx_priv *priv)
*
* Pushes desc to TxD fifo and overlaps it if needed.
* NOTE: this func does not check for available space. this is responsibility
- * of the caller. Neither does it check that data size is smaller then
+ * of the caller. Neither does it check that data size is smaller than
* fifo size.
*/
static void bdx_tx_push_desc(struct bdx_priv *priv, void *data, int size)
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 85ef8b744557..68b967b585aa 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -831,6 +831,21 @@ static void TLan_Poll(struct net_device *dev)
}
#endif
+static const struct net_device_ops TLan_netdev_ops = {
+ .ndo_open = TLan_Open,
+ .ndo_stop = TLan_Close,
+ .ndo_start_xmit = TLan_StartTx,
+ .ndo_tx_timeout = TLan_tx_timeout,
+ .ndo_get_stats = TLan_GetStats,
+ .ndo_set_multicast_list = TLan_SetMulticastList,
+ .ndo_do_ioctl = TLan_ioctl,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = TLan_Poll,
+#endif
+};
@@ -892,16 +907,7 @@ static int TLan_Init( struct net_device *dev )
netif_carrier_off(dev);
/* Device methods */
- dev->open = &TLan_Open;
- dev->hard_start_xmit = &TLan_StartTx;
- dev->stop = &TLan_Close;
- dev->get_stats = &TLan_GetStats;
- dev->set_multicast_list = &TLan_SetMulticastList;
- dev->do_ioctl = &TLan_ioctl;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = &TLan_Poll;
-#endif
- dev->tx_timeout = &TLan_tx_timeout;
+ dev->netdev_ops = &TLan_netdev_ops;
dev->watchdog_timeo = TX_TIMEOUT;
return 0;
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index a011666342ff..50eb29ce3c87 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -3064,7 +3064,7 @@ static int smctr_load_node_addr(struct net_device *dev)
* will consequently cause a timeout.
*
* NOTE 1: If the monitor_state is MS_BEACON_TEST_STATE, all transmit
- * queues other then the one used for the lobe_media_test should be
+ * queues other than the one used for the lobe_media_test should be
* disabled.!?
*
* NOTE 2: If the monitor_state is MS_BEACON_TEST_STATE and the receive_mask
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index 5166be930a52..d5d53b633cf8 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -1922,6 +1922,18 @@ bad_srom:
goto fill_defaults;
}
+static const struct net_device_ops de_netdev_ops = {
+ .ndo_open = de_open,
+ .ndo_stop = de_close,
+ .ndo_set_multicast_list = de_set_rx_mode,
+ .ndo_start_xmit = de_start_xmit,
+ .ndo_get_stats = de_get_stats,
+ .ndo_tx_timeout = de_tx_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
static int __devinit de_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -1944,14 +1956,9 @@ static int __devinit de_init_one (struct pci_dev *pdev,
if (!dev)
return -ENOMEM;
+ dev->netdev_ops = &de_netdev_ops;
SET_NETDEV_DEV(dev, &pdev->dev);
- dev->open = de_open;
- dev->stop = de_close;
- dev->set_multicast_list = de_set_rx_mode;
- dev->hard_start_xmit = de_start_xmit;
- dev->get_stats = de_get_stats;
dev->ethtool_ops = &de_ethtool_ops;
- dev->tx_timeout = de_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
de = netdev_priv(dev);
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 67bfd6f43366..6418f74415d7 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -1077,6 +1077,18 @@ static int (*dc_infoblock[])(struct net_device *dev, u_char, u_char *) = {
mdelay(2); /* Wait for 2ms */\
}
+static const struct net_device_ops de4x5_netdev_ops = {
+ .ndo_open = de4x5_open,
+ .ndo_stop = de4x5_close,
+ .ndo_start_xmit = de4x5_queue_pkt,
+ .ndo_get_stats = de4x5_get_stats,
+ .ndo_set_multicast_list = set_multicast_list,
+ .ndo_do_ioctl = de4x5_ioctl,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address= eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
static int __devinit
de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
@@ -1258,13 +1270,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
/* The DE4X5-specific entries in the device structure. */
SET_NETDEV_DEV(dev, gendev);
- dev->open = &de4x5_open;
- dev->hard_start_xmit = &de4x5_queue_pkt;
- dev->stop = &de4x5_close;
- dev->get_stats = &de4x5_get_stats;
- dev->set_multicast_list = &set_multicast_list;
- dev->do_ioctl = &de4x5_ioctl;
-
+ dev->netdev_ops = &de4x5_netdev_ops;
dev->mem_start = 0;
/* Fill in the generic fields of the device structure. */
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 28a5c51b43a0..2e5c99941f35 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -257,9 +257,6 @@ struct dmfe_board_info {
u8 wol_mode; /* user WOL settings */
struct timer_list timer;
- /* System defined statistic counter */
- struct net_device_stats stats;
-
/* Driver defined statistic counter */
unsigned long tx_fifo_underrun;
unsigned long tx_loss_carrier;
@@ -316,7 +313,6 @@ static u8 SF_mode; /* Special Function: 1:VLAN, 2:RX Flow Control
static int dmfe_open(struct DEVICE *);
static int dmfe_start_xmit(struct sk_buff *, struct DEVICE *);
static int dmfe_stop(struct DEVICE *);
-static struct net_device_stats * dmfe_get_stats(struct DEVICE *);
static void dmfe_set_filter_mode(struct DEVICE *);
static const struct ethtool_ops netdev_ethtool_ops;
static u16 read_srom_word(long ,int);
@@ -351,6 +347,19 @@ static void dmfe_set_phyxcer(struct dmfe_board_info *);
/* DM910X network board routine ---------------------------- */
+static const struct net_device_ops netdev_ops = {
+ .ndo_open = dmfe_open,
+ .ndo_stop = dmfe_stop,
+ .ndo_start_xmit = dmfe_start_xmit,
+ .ndo_set_multicast_list = dmfe_set_filter_mode,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = poll_dmfe,
+#endif
+};
+
/*
* Search DM910X board ,allocate space and register it
*/
@@ -442,14 +451,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
dev->base_addr = db->ioaddr;
dev->irq = pdev->irq;
pci_set_drvdata(pdev, dev);
- dev->open = &dmfe_open;
- dev->hard_start_xmit = &dmfe_start_xmit;
- dev->stop = &dmfe_stop;
- dev->get_stats = &dmfe_get_stats;
- dev->set_multicast_list = &dmfe_set_filter_mode;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = &poll_dmfe;
-#endif
+ dev->netdev_ops = &netdev_ops;
dev->ethtool_ops = &netdev_ethtool_ops;
netif_carrier_off(dev);
spin_lock_init(&db->lock);
@@ -867,15 +869,15 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
/* A packet sent completed */
db->tx_packet_cnt--;
- db->stats.tx_packets++;
+ dev->stats.tx_packets++;
/* Transmit statistic counter */
if ( tdes0 != 0x7fffffff ) {
/* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
- db->stats.collisions += (tdes0 >> 3) & 0xf;
- db->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
+ dev->stats.collisions += (tdes0 >> 3) & 0xf;
+ dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
if (tdes0 & TDES0_ERR_MASK) {
- db->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (tdes0 & 0x0002) { /* UnderRun */
db->tx_fifo_underrun++;
@@ -969,13 +971,13 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
if (rdes0 & 0x8000) {
/* This is a error packet */
//printk(DRV_NAME ": rdes0: %lx\n", rdes0);
- db->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rdes0 & 1)
- db->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (rdes0 & 2)
- db->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rdes0 & 0x80)
- db->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
if ( !(rdes0 & 0x8000) ||
@@ -1008,8 +1010,8 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- db->stats.rx_packets++;
- db->stats.rx_bytes += rxlen;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += rxlen;
}
} else {
/* Reuse SKB buffer when the packet is error */
@@ -1024,20 +1026,6 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
db->rx_ready_ptr = rxptr;
}
-
-/*
- * Get statistics from driver.
- */
-
-static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev)
-{
- struct dmfe_board_info *db = netdev_priv(dev);
-
- DMFE_DBUG(0, "dmfe_get_stats", 0);
- return &db->stats;
-}
-
-
/*
* Set DM910X multicast address
*/
@@ -1161,7 +1149,7 @@ static void dmfe_timer(unsigned long data)
/* Operating Mode Check */
if ( (db->dm910x_chk_mode & 0x1) &&
- (db->stats.rx_packets > MAX_CHECK_PACKET) )
+ (dev->stats.rx_packets > MAX_CHECK_PACKET) )
db->dm910x_chk_mode = 0x4;
/* Dynamic reset DM910X : system error or transmit time-out */
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index ff84babb3ff3..bee75fa87a9c 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1225,6 +1225,22 @@ static int tulip_uli_dm_quirk(struct pci_dev *pdev)
return 0;
}
+static const struct net_device_ops tulip_netdev_ops = {
+ .ndo_open = tulip_open,
+ .ndo_start_xmit = tulip_start_xmit,
+ .ndo_tx_timeout = tulip_tx_timeout,
+ .ndo_stop = tulip_close,
+ .ndo_get_stats = tulip_get_stats,
+ .ndo_do_ioctl = private_ioctl,
+ .ndo_set_multicast_list = set_rx_mode,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = poll_tulip,
+#endif
+};
+
static int __devinit tulip_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -1601,20 +1617,11 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
}
/* The Tulip-specific entries in the device structure. */
- dev->open = tulip_open;
- dev->hard_start_xmit = tulip_start_xmit;
- dev->tx_timeout = tulip_tx_timeout;
+ dev->netdev_ops = &tulip_netdev_ops;
dev->watchdog_timeo = TX_TIMEOUT;
#ifdef CONFIG_TULIP_NAPI
netif_napi_add(dev, &tp->napi, tulip_poll, 16);
#endif
- dev->stop = tulip_close;
- dev->get_stats = tulip_get_stats;
- dev->do_ioctl = private_ioctl;
- dev->set_multicast_list = set_rx_mode;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = &poll_tulip;
-#endif
SET_ETHTOOL_OPS(dev, &ops);
if (register_netdev(dev))
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index 00cbc5251dcc..030e02e63023 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -168,9 +168,6 @@ struct uli526x_board_info {
u8 wait_reset; /* Hardware failed, need to reset */
struct timer_list timer;
- /* System defined statistic counter */
- struct net_device_stats stats;
-
/* Driver defined statistic counter */
unsigned long tx_fifo_underrun;
unsigned long tx_loss_carrier;
@@ -220,7 +217,6 @@ static int mode = 8;
static int uli526x_open(struct net_device *);
static int uli526x_start_xmit(struct sk_buff *, struct net_device *);
static int uli526x_stop(struct net_device *);
-static struct net_device_stats * uli526x_get_stats(struct net_device *);
static void uli526x_set_filter_mode(struct net_device *);
static const struct ethtool_ops netdev_ethtool_ops;
static u16 read_srom_word(long, int);
@@ -251,6 +247,19 @@ static void uli526x_set_phyxcer(struct uli526x_board_info *);
/* ULI526X network board routine ---------------------------- */
+static const struct net_device_ops netdev_ops = {
+ .ndo_open = uli526x_open,
+ .ndo_stop = uli526x_stop,
+ .ndo_start_xmit = uli526x_start_xmit,
+ .ndo_set_multicast_list = uli526x_set_filter_mode,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = uli526x_poll,
+#endif
+};
+
/*
* Search ULI526X board, allocate space and register it
*/
@@ -335,15 +344,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
pci_set_drvdata(pdev, dev);
/* Register some necessary functions */
- dev->open = &uli526x_open;
- dev->hard_start_xmit = &uli526x_start_xmit;
- dev->stop = &uli526x_stop;
- dev->get_stats = &uli526x_get_stats;
- dev->set_multicast_list = &uli526x_set_filter_mode;
+ dev->netdev_ops = &netdev_ops;
dev->ethtool_ops = &netdev_ethtool_ops;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = &uli526x_poll;
-#endif
+
spin_lock_init(&db->lock);
@@ -733,7 +736,8 @@ static void uli526x_poll(struct net_device *dev)
* Free TX resource after TX complete
*/
-static void uli526x_free_tx_pkt(struct net_device *dev, struct uli526x_board_info * db)
+static void uli526x_free_tx_pkt(struct net_device *dev,
+ struct uli526x_board_info * db)
{
struct tx_desc *txptr;
u32 tdes0;
@@ -747,15 +751,15 @@ static void uli526x_free_tx_pkt(struct net_device *dev, struct uli526x_board_inf
/* A packet sent completed */
db->tx_packet_cnt--;
- db->stats.tx_packets++;
+ dev->stats.tx_packets++;
/* Transmit statistic counter */
if ( tdes0 != 0x7fffffff ) {
/* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
- db->stats.collisions += (tdes0 >> 3) & 0xf;
- db->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
+ dev->stats.collisions += (tdes0 >> 3) & 0xf;
+ dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
if (tdes0 & TDES0_ERR_MASK) {
- db->stats.tx_errors++;
+ dev->stats.tx_errors++;
if (tdes0 & 0x0002) { /* UnderRun */
db->tx_fifo_underrun++;
if ( !(db->cr6_data & CR6_SFT) ) {
@@ -825,13 +829,13 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info
if (rdes0 & 0x8000) {
/* This is a error packet */
//printk(DRV_NAME ": rdes0: %lx\n", rdes0);
- db->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rdes0 & 1)
- db->stats.rx_fifo_errors++;
+ dev->stats.rx_fifo_errors++;
if (rdes0 & 2)
- db->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rdes0 & 0x80)
- db->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
}
if ( !(rdes0 & 0x8000) ||
@@ -854,8 +858,8 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- db->stats.rx_packets++;
- db->stats.rx_bytes += rxlen;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += rxlen;
} else {
/* Reuse SKB buffer when the packet is error */
@@ -872,19 +876,6 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info
/*
- * Get statistics from driver.
- */
-
-static struct net_device_stats * uli526x_get_stats(struct net_device *dev)
-{
- struct uli526x_board_info *db = netdev_priv(dev);
-
- ULI526X_DBUG(0, "uli526x_get_stats", 0);
- return &db->stats;
-}
-
-
-/*
* Set ULI526X multicast address
*/
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 022d99af8646..f467bf87817d 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -343,7 +343,18 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static const struct ethtool_ops netdev_ethtool_ops;
static int netdev_close(struct net_device *dev);
-
+static const struct net_device_ops netdev_ops = {
+ .ndo_open = netdev_open,
+ .ndo_stop = netdev_close,
+ .ndo_start_xmit = start_tx,
+ .ndo_get_stats = get_stats,
+ .ndo_set_multicast_list = set_rx_mode,
+ .ndo_do_ioctl = netdev_ioctl,
+ .ndo_tx_timeout = tx_timeout,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
static int __devinit w840_probe1 (struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -420,14 +431,8 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
np->mii_if.force_media = 1;
/* The chip-specific entries in the device structure. */
- dev->open = &netdev_open;
- dev->hard_start_xmit = &start_tx;
- dev->stop = &netdev_close;
- dev->get_stats = &get_stats;
- dev->set_multicast_list = &set_rx_mode;
- dev->do_ioctl = &netdev_ioctl;
+ dev->netdev_ops = &netdev_ops;
dev->ethtool_ops = &netdev_ethtool_ops;
- dev->tx_timeout = &tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
i = register_netdev(dev);
@@ -1555,7 +1560,7 @@ static void __devexit w840_remove1 (struct pci_dev *pdev)
* rtnl_lock, & netif_device_detach after the rtnl_unlock.
* - get_stats:
* spin_lock_irq(np->lock), doesn't touch hw if not present
- * - hard_start_xmit:
+ * - start_xmit:
* synchronize_irq + netif_tx_disable;
* - tx_timeout:
* netif_device_detach + netif_tx_disable;
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 13c8703ecb9f..c2ca9f40e40e 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -104,10 +104,8 @@ struct xircom_private {
*/
spinlock_t lock;
-
struct pci_dev *pdev;
struct net_device *dev;
- struct net_device_stats stats;
};
@@ -119,7 +117,6 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int xircom_open(struct net_device *dev);
static int xircom_close(struct net_device *dev);
static void xircom_up(struct xircom_private *card);
-static struct net_device_stats *xircom_get_stats(struct net_device *dev);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void xircom_poll_controller(struct net_device *dev);
#endif
@@ -194,6 +191,18 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
};
+static const struct net_device_ops netdev_ops = {
+ .ndo_open = xircom_open,
+ .ndo_stop = xircom_close,
+ .ndo_start_xmit = xircom_start_xmit,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = xircom_poll_controller,
+#endif
+};
+
/* xircom_probe is the code that gets called on device insertion.
it sets up the hardware and registers the device to the networklayer.
@@ -266,13 +275,7 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
read_mac_address(private);
setup_descriptors(private);
- dev->open = &xircom_open;
- dev->hard_start_xmit = &xircom_start_xmit;
- dev->stop = &xircom_close;
- dev->get_stats = &xircom_get_stats;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = &xircom_poll_controller;
-#endif
+ dev->netdev_ops = &netdev_ops;
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
pci_set_drvdata(pdev, dev);
@@ -497,14 +500,6 @@ static int xircom_close(struct net_device *dev)
}
-
-static struct net_device_stats *xircom_get_stats(struct net_device *dev)
-{
- struct xircom_private *card = netdev_priv(dev);
- return &card->stats;
-}
-
-
#ifdef CONFIG_NET_POLL_CONTROLLER
static void xircom_poll_controller(struct net_device *dev)
{
@@ -1193,7 +1188,7 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri
skb = dev_alloc_skb(pkt_len + 2);
if (skb == NULL) {
- card->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto out;
}
skb_reserve(skb, 2);
@@ -1201,8 +1196,8 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
- card->stats.rx_packets++;
- card->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
out:
/* give the buffer back to the card */
@@ -1232,16 +1227,16 @@ static void investigate_write_descriptor(struct net_device *dev, struct xircom_p
#endif
if (status > 0) { /* bit 31 is 0 when done */
if (card->tx_skb[descnr]!=NULL) {
- card->stats.tx_bytes += card->tx_skb[descnr]->len;
+ dev->stats.tx_bytes += card->tx_skb[descnr]->len;
dev_kfree_skb_irq(card->tx_skb[descnr]);
}
card->tx_skb[descnr] = NULL;
/* Bit 8 in the status field is 1 if there was a collision */
if (status&(1<<8))
- card->stats.collisions++;
+ dev->stats.collisions++;
card->tx_buffer[4*descnr] = 0; /* descriptor is free again */
netif_wake_queue (dev);
- card->stats.tx_packets++;
+ dev->stats.tx_packets++;
}
leave("investigate_write_descriptor");
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 0009f4e34433..3af9a9516ccb 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -2296,6 +2296,19 @@ out:
return mode;
}
+static const struct net_device_ops typhoon_netdev_ops = {
+ .ndo_open = typhoon_open,
+ .ndo_stop = typhoon_close,
+ .ndo_start_xmit = typhoon_start_tx,
+ .ndo_set_multicast_list = typhoon_set_rx_mode,
+ .ndo_tx_timeout = typhoon_tx_timeout,
+ .ndo_get_stats = typhoon_get_stats,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = typhoon_set_mac_address,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_vlan_rx_register = typhoon_vlan_rx_register,
+};
+
static int __devinit
typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -2495,16 +2508,9 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* The chip-specific entries in the device structure. */
- dev->open = typhoon_open;
- dev->hard_start_xmit = typhoon_start_tx;
- dev->stop = typhoon_close;
- dev->set_multicast_list = typhoon_set_rx_mode;
- dev->tx_timeout = typhoon_tx_timeout;
+ dev->netdev_ops = &typhoon_netdev_ops;
netif_napi_add(dev, &tp->napi, typhoon_poll, 16);
dev->watchdog_timeo = TX_TIMEOUT;
- dev->get_stats = typhoon_get_stats;
- dev->set_mac_address = typhoon_set_mac_address;
- dev->vlan_rx_register = typhoon_vlan_rx_register;
SET_ETHTOOL_OPS(dev, &typhoon_ethtool_ops);
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 7d5a1303e30d..11441225bf41 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -442,40 +442,30 @@ static void magic_packet_detection_enable(struct ucc_geth_private *ugeth)
{
struct ucc_fast_private *uccf;
struct ucc_geth __iomem *ug_regs;
- u32 maccfg2, uccm;
uccf = ugeth->uccf;
ug_regs = ugeth->ug_regs;
/* Enable interrupts for magic packet detection */
- uccm = in_be32(uccf->p_uccm);
- uccm |= UCCE_MPD;
- out_be32(uccf->p_uccm, uccm);
+ setbits32(uccf->p_uccm, UCC_GETH_UCCE_MPD);
/* Enable magic packet detection */
- maccfg2 = in_be32(&ug_regs->maccfg2);
- maccfg2 |= MACCFG2_MPE;
- out_be32(&ug_regs->maccfg2, maccfg2);
+ setbits32(&ug_regs->maccfg2, MACCFG2_MPE);
}
static void magic_packet_detection_disable(struct ucc_geth_private *ugeth)
{
struct ucc_fast_private *uccf;
struct ucc_geth __iomem *ug_regs;
- u32 maccfg2, uccm;
uccf = ugeth->uccf;
ug_regs = ugeth->ug_regs;
/* Disable interrupts for magic packet detection */
- uccm = in_be32(uccf->p_uccm);
- uccm &= ~UCCE_MPD;
- out_be32(uccf->p_uccm, uccm);
+ clrbits32(uccf->p_uccm, UCC_GETH_UCCE_MPD);
/* Disable magic packet detection */
- maccfg2 = in_be32(&ug_regs->maccfg2);
- maccfg2 &= ~MACCFG2_MPE;
- out_be32(&ug_regs->maccfg2, maccfg2);
+ clrbits32(&ug_regs->maccfg2, MACCFG2_MPE);
}
#endif /* MAGIC_PACKET */
@@ -585,7 +575,8 @@ static void get_statistics(struct ucc_geth_private *ugeth,
/* Hardware only if user handed pointer and driver actually
gathers hardware statistics */
- if (hardware_statistics && (in_be32(&uf_regs->upsmr) & UPSMR_HSE)) {
+ if (hardware_statistics &&
+ (in_be32(&uf_regs->upsmr) & UCC_GETH_UPSMR_HSE)) {
hardware_statistics->tx64 = in_be32(&ug_regs->tx64);
hardware_statistics->tx127 = in_be32(&ug_regs->tx127);
hardware_statistics->tx255 = in_be32(&ug_regs->tx255);
@@ -1181,9 +1172,7 @@ int init_flow_control_params(u32 automatic_flow_control_mode,
out_be32(uempr_register, value);
/* Set UPSMR register */
- value = in_be32(upsmr_register);
- value |= automatic_flow_control_mode;
- out_be32(upsmr_register, value);
+ setbits32(upsmr_register, automatic_flow_control_mode);
value = in_be32(maccfg1_register);
if (rx_flow_control_enable)
@@ -1200,14 +1189,11 @@ static int init_hw_statistics_gathering_mode(int enable_hardware_statistics,
u32 __iomem *upsmr_register,
u16 __iomem *uescr_register)
{
- u32 upsmr_value = 0;
u16 uescr_value = 0;
+
/* Enable hardware statistics gathering if requested */
- if (enable_hardware_statistics) {
- upsmr_value = in_be32(upsmr_register);
- upsmr_value |= UPSMR_HSE;
- out_be32(upsmr_register, upsmr_value);
- }
+ if (enable_hardware_statistics)
+ setbits32(upsmr_register, UCC_GETH_UPSMR_HSE);
/* Clear hardware statistics counters */
uescr_value = in_be16(uescr_register);
@@ -1233,23 +1219,17 @@ static int init_firmware_statistics_gathering_mode(int
{
/* Note: this function does not check if */
/* the parameters it receives are NULL */
- u16 temoder_value;
- u32 remoder_value;
if (enable_tx_firmware_statistics) {
out_be32(tx_rmon_base_ptr,
tx_firmware_statistics_structure_address);
- temoder_value = in_be16(temoder_register);
- temoder_value |= TEMODER_TX_RMON_STATISTICS_ENABLE;
- out_be16(temoder_register, temoder_value);
+ setbits16(temoder_register, TEMODER_TX_RMON_STATISTICS_ENABLE);
}
if (enable_rx_firmware_statistics) {
out_be32(rx_rmon_base_ptr,
rx_firmware_statistics_structure_address);
- remoder_value = in_be32(remoder_register);
- remoder_value |= REMODER_RX_RMON_STATISTICS_ENABLE;
- out_be32(remoder_register, remoder_value);
+ setbits32(remoder_register, REMODER_RX_RMON_STATISTICS_ENABLE);
}
return 0;
@@ -1316,15 +1296,12 @@ static int init_check_frame_length_mode(int length_check,
static int init_preamble_length(u8 preamble_length,
u32 __iomem *maccfg2_register)
{
- u32 value = 0;
-
if ((preamble_length < 3) || (preamble_length > 7))
return -EINVAL;
- value = in_be32(maccfg2_register);
- value &= ~MACCFG2_PREL_MASK;
- value |= (preamble_length << MACCFG2_PREL_SHIFT);
- out_be32(maccfg2_register, value);
+ clrsetbits_be32(maccfg2_register, MACCFG2_PREL_MASK,
+ preamble_length << MACCFG2_PREL_SHIFT);
+
return 0;
}
@@ -1337,19 +1314,19 @@ static int init_rx_parameters(int reject_broadcast,
value = in_be32(upsmr_register);
if (reject_broadcast)
- value |= UPSMR_BRO;
+ value |= UCC_GETH_UPSMR_BRO;
else
- value &= ~UPSMR_BRO;
+ value &= ~UCC_GETH_UPSMR_BRO;
if (receive_short_frames)
- value |= UPSMR_RSH;
+ value |= UCC_GETH_UPSMR_RSH;
else
- value &= ~UPSMR_RSH;
+ value &= ~UCC_GETH_UPSMR_RSH;
if (promiscuous)
- value |= UPSMR_PRO;
+ value |= UCC_GETH_UPSMR_PRO;
else
- value &= ~UPSMR_PRO;
+ value &= ~UCC_GETH_UPSMR_PRO;
out_be32(upsmr_register, value);
@@ -1410,26 +1387,27 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
/* Set UPSMR */
upsmr = in_be32(&uf_regs->upsmr);
- upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM);
+ upsmr &= ~(UCC_GETH_UPSMR_RPM | UCC_GETH_UPSMR_R10M |
+ UCC_GETH_UPSMR_TBIM | UCC_GETH_UPSMR_RMM);
if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
- upsmr |= UPSMR_RPM;
+ upsmr |= UCC_GETH_UPSMR_RPM;
switch (ugeth->max_speed) {
case SPEED_10:
- upsmr |= UPSMR_R10M;
+ upsmr |= UCC_GETH_UPSMR_R10M;
/* FALLTHROUGH */
case SPEED_100:
if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI)
- upsmr |= UPSMR_RMM;
+ upsmr |= UCC_GETH_UPSMR_RMM;
}
}
if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
- upsmr |= UPSMR_TBIM;
+ upsmr |= UCC_GETH_UPSMR_TBIM;
}
out_be32(&uf_regs->upsmr, upsmr);
@@ -1517,9 +1495,9 @@ static void adjust_link(struct net_device *dev)
(ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
if (phydev->speed == SPEED_10)
- upsmr |= UPSMR_R10M;
+ upsmr |= UCC_GETH_UPSMR_R10M;
else
- upsmr &= ~(UPSMR_R10M);
+ upsmr &= ~UCC_GETH_UPSMR_R10M;
}
break;
default:
@@ -1602,10 +1580,8 @@ static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
uccf = ugeth->uccf;
/* Mask GRACEFUL STOP TX interrupt bit and clear it */
- temp = in_be32(uccf->p_uccm);
- temp &= ~UCCE_GRA;
- out_be32(uccf->p_uccm, temp);
- out_be32(uccf->p_ucce, UCCE_GRA); /* clear by writing 1 */
+ clrbits32(uccf->p_uccm, UCC_GETH_UCCE_GRA);
+ out_be32(uccf->p_ucce, UCC_GETH_UCCE_GRA); /* clear by writing 1 */
/* Issue host command */
cecr_subblock =
@@ -1617,7 +1593,7 @@ static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
do {
msleep(10);
temp = in_be32(uccf->p_ucce);
- } while (!(temp & UCCE_GRA) && --i);
+ } while (!(temp & UCC_GETH_UCCE_GRA) && --i);
uccf->stopped_tx = 1;
@@ -1975,12 +1951,9 @@ static void ucc_geth_set_multi(struct net_device *dev)
uf_regs = ugeth->uccf->uf_regs;
if (dev->flags & IFF_PROMISC) {
-
- out_be32(&uf_regs->upsmr, in_be32(&uf_regs->upsmr) | UPSMR_PRO);
-
+ setbits32(&uf_regs->upsmr, UCC_GETH_UPSMR_PRO);
} else {
-
- out_be32(&uf_regs->upsmr, in_be32(&uf_regs->upsmr)&~UPSMR_PRO);
+ clrbits32(&uf_regs->upsmr, UCC_GETH_UPSMR_PRO);
p_82xx_addr_filt =
(struct ucc_geth_82xx_address_filtering_pram __iomem *) ugeth->
@@ -2020,7 +1993,6 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
{
struct ucc_geth __iomem *ug_regs = ugeth->ug_regs;
struct phy_device *phydev = ugeth->phydev;
- u32 tempval;
ugeth_vdbg("%s: IN", __func__);
@@ -2037,9 +2009,7 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
out_be32(ugeth->uccf->p_ucce, 0xffffffff);
/* Disable Rx and Tx */
- tempval = in_be32(&ug_regs->maccfg1);
- tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
- out_be32(&ug_regs->maccfg1, tempval);
+ clrbits32(&ug_regs->maccfg1, MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
ucc_geth_memclean(ugeth);
}
@@ -2153,10 +2123,10 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
/* Generate uccm_mask for receive */
uf_info->uccm_mask = ug_info->eventRegMask & UCCE_OTHER;/* Errors */
for (i = 0; i < ug_info->numQueuesRx; i++)
- uf_info->uccm_mask |= (UCCE_RXBF_SINGLE_MASK << i);
+ uf_info->uccm_mask |= (UCC_GETH_UCCE_RXF0 << i);
for (i = 0; i < ug_info->numQueuesTx; i++)
- uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i);
+ uf_info->uccm_mask |= (UCC_GETH_UCCE_TXB0 << i);
/* Initialize the general fast UCC block. */
if (ucc_fast_init(uf_info, &ugeth->uccf)) {
if (netif_msg_probe(ugeth))
@@ -2185,7 +2155,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
struct ucc_geth __iomem *ug_regs;
int ret_val = -EINVAL;
u32 remoder = UCC_GETH_REMODER_INIT;
- u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
+ u32 init_enet_pram_offset, cecr_subblock, command;
u32 ifstat, i, j, size, l2qt, l3qt, length;
u16 temoder = UCC_GETH_TEMODER_INIT;
u16 test;
@@ -2281,10 +2251,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
&uf_regs->upsmr,
&ug_regs->uempr, &ug_regs->maccfg1);
- maccfg1 = in_be32(&ug_regs->maccfg1);
- maccfg1 |= MACCFG1_ENABLE_RX;
- maccfg1 |= MACCFG1_ENABLE_TX;
- out_be32(&ug_regs->maccfg1, maccfg1);
+ setbits32(&ug_regs->maccfg1, MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
/* Set IPGIFG */
/* For more details see the hardware spec. */
@@ -3274,7 +3241,6 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
static int ucc_geth_poll(struct napi_struct *napi, int budget)
{
struct ucc_geth_private *ugeth = container_of(napi, struct ucc_geth_private, napi);
- struct net_device *dev = ugeth->dev;
struct ucc_geth_info *ug_info;
int howmany, i;
@@ -3285,14 +3251,8 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget)
howmany += ucc_geth_rx(ugeth, i, budget - howmany);
if (howmany < budget) {
- struct ucc_fast_private *uccf;
- u32 uccm;
-
netif_rx_complete(napi);
- uccf = ugeth->uccf;
- uccm = in_be32(uccf->p_uccm);
- uccm |= UCCE_RX_EVENTS;
- out_be32(uccf->p_uccm, uccm);
+ setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS);
}
return howmany;
@@ -3332,7 +3292,7 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
/* Tx event processing */
if (ucce & UCCE_TX_EVENTS) {
spin_lock(&ugeth->lock);
- tx_mask = UCCE_TXBF_SINGLE_MASK;
+ tx_mask = UCC_GETH_UCCE_TXB0;
for (i = 0; i < ug_info->numQueuesTx; i++) {
if (ucce & tx_mask)
ucc_geth_tx(dev, i);
@@ -3344,12 +3304,10 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
/* Errors and other events */
if (ucce & UCCE_OTHER) {
- if (ucce & UCCE_BSY) {
+ if (ucce & UCC_GETH_UCCE_BSY)
dev->stats.rx_errors++;
- }
- if (ucce & UCCE_TXE) {
+ if (ucce & UCC_GETH_UCCE_TXE)
dev->stats.tx_errors++;
- }
}
return IRQ_HANDLED;
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index d74d2f7cb739..8f699cb773ee 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -162,92 +162,27 @@ struct ucc_geth {
boundary */
/* UCC GETH Event Register */
-#define UCCE_MPD 0x80000000 /* Magic packet
- detection */
-#define UCCE_SCAR 0x40000000
-#define UCCE_GRA 0x20000000 /* Tx graceful
- stop
- complete */
-#define UCCE_CBPR 0x10000000
-#define UCCE_BSY 0x08000000
-#define UCCE_RXC 0x04000000
-#define UCCE_TXC 0x02000000
-#define UCCE_TXE 0x01000000
-#define UCCE_TXB7 0x00800000
-#define UCCE_TXB6 0x00400000
-#define UCCE_TXB5 0x00200000
-#define UCCE_TXB4 0x00100000
-#define UCCE_TXB3 0x00080000
-#define UCCE_TXB2 0x00040000
-#define UCCE_TXB1 0x00020000
-#define UCCE_TXB0 0x00010000
-#define UCCE_RXB7 0x00008000
-#define UCCE_RXB6 0x00004000
-#define UCCE_RXB5 0x00002000
-#define UCCE_RXB4 0x00001000
-#define UCCE_RXB3 0x00000800
-#define UCCE_RXB2 0x00000400
-#define UCCE_RXB1 0x00000200
-#define UCCE_RXB0 0x00000100
-#define UCCE_RXF7 0x00000080
-#define UCCE_RXF6 0x00000040
-#define UCCE_RXF5 0x00000020
-#define UCCE_RXF4 0x00000010
-#define UCCE_RXF3 0x00000008
-#define UCCE_RXF2 0x00000004
-#define UCCE_RXF1 0x00000002
-#define UCCE_RXF0 0x00000001
-
-#define UCCE_RXBF_SINGLE_MASK (UCCE_RXF0)
-#define UCCE_TXBF_SINGLE_MASK (UCCE_TXB0)
-
-#define UCCE_TXB (UCCE_TXB7 | UCCE_TXB6 | UCCE_TXB5 | UCCE_TXB4 |\
- UCCE_TXB3 | UCCE_TXB2 | UCCE_TXB1 | UCCE_TXB0)
-#define UCCE_RXB (UCCE_RXB7 | UCCE_RXB6 | UCCE_RXB5 | UCCE_RXB4 |\
- UCCE_RXB3 | UCCE_RXB2 | UCCE_RXB1 | UCCE_RXB0)
-#define UCCE_RXF (UCCE_RXF7 | UCCE_RXF6 | UCCE_RXF5 | UCCE_RXF4 |\
- UCCE_RXF3 | UCCE_RXF2 | UCCE_RXF1 | UCCE_RXF0)
-#define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY |\
- UCCE_RXC | UCCE_TXC | UCCE_TXE)
-
-#define UCCE_RX_EVENTS (UCCE_RXF | UCCE_BSY)
-#define UCCE_TX_EVENTS (UCCE_TXB | UCCE_TXE)
-
-/* UCC GETH UPSMR (Protocol Specific Mode Register) */
-#define UPSMR_ECM 0x04000000 /* Enable CAM
- Miss or
- Enable
- Filtering
- Miss */
-#define UPSMR_HSE 0x02000000 /* Hardware
- Statistics
- Enable */
-#define UPSMR_PRO 0x00400000 /* Promiscuous*/
-#define UPSMR_CAP 0x00200000 /* CAM polarity
- */
-#define UPSMR_RSH 0x00100000 /* Receive
- Short Frames
- */
-#define UPSMR_RPM 0x00080000 /* Reduced Pin
- Mode
- interfaces */
-#define UPSMR_R10M 0x00040000 /* RGMII/RMII
- 10 Mode */
-#define UPSMR_RLPB 0x00020000 /* RMII
- Loopback
- Mode */
-#define UPSMR_TBIM 0x00010000 /* Ten-bit
- Interface
- Mode */
-#define UPSMR_RMM 0x00001000 /* RMII/RGMII
- Mode */
-#define UPSMR_CAM 0x00000400 /* CAM Address
- Matching */
-#define UPSMR_BRO 0x00000200 /* Broadcast
- Address */
-#define UPSMR_RES1 0x00002000 /* Reserved
- feild - must
- be 1 */
+#define UCCE_TXB (UCC_GETH_UCCE_TXB7 | UCC_GETH_UCCE_TXB6 | \
+ UCC_GETH_UCCE_TXB5 | UCC_GETH_UCCE_TXB4 | \
+ UCC_GETH_UCCE_TXB3 | UCC_GETH_UCCE_TXB2 | \
+ UCC_GETH_UCCE_TXB1 | UCC_GETH_UCCE_TXB0)
+
+#define UCCE_RXB (UCC_GETH_UCCE_RXB7 | UCC_GETH_UCCE_RXB6 | \
+ UCC_GETH_UCCE_RXB5 | UCC_GETH_UCCE_RXB4 | \
+ UCC_GETH_UCCE_RXB3 | UCC_GETH_UCCE_RXB2 | \
+ UCC_GETH_UCCE_RXB1 | UCC_GETH_UCCE_RXB0)
+
+#define UCCE_RXF (UCC_GETH_UCCE_RXF7 | UCC_GETH_UCCE_RXF6 | \
+ UCC_GETH_UCCE_RXF5 | UCC_GETH_UCCE_RXF4 | \
+ UCC_GETH_UCCE_RXF3 | UCC_GETH_UCCE_RXF2 | \
+ UCC_GETH_UCCE_RXF1 | UCC_GETH_UCCE_RXF0)
+
+#define UCCE_OTHER (UCC_GETH_UCCE_SCAR | UCC_GETH_UCCE_GRA | \
+ UCC_GETH_UCCE_CBPR | UCC_GETH_UCCE_BSY | \
+ UCC_GETH_UCCE_RXC | UCC_GETH_UCCE_TXC | UCC_GETH_UCCE_TXE)
+
+#define UCCE_RX_EVENTS (UCCE_RXF | UCC_GETH_UCCE_BSY)
+#define UCCE_TX_EVENTS (UCCE_TXB | UCC_GETH_UCCE_TXE)
/* UCC GETH MACCFG1 (MAC Configuration 1 Register) */
#define MACCFG1_FLOW_RX 0x00000020 /* Flow Control
@@ -945,9 +880,10 @@ struct ucc_geth_hardware_statistics {
#define UCC_GETH_REMODER_INIT 0 /* bits that must be
set */
#define UCC_GETH_TEMODER_INIT 0xC000 /* bits that must */
-#define UCC_GETH_UPSMR_INIT (UPSMR_RES1) /* Start value
- for this
- register */
+
+/* Initial value for UPSMR */
+#define UCC_GETH_UPSMR_INIT UCC_GETH_UPSMR_RES1
+
#define UCC_GETH_MACCFG1_INIT 0
#define UCC_GETH_MACCFG2_INIT (MACCFG2_RESERVED_1)
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index edd244f3acb5..5b67bbf1987e 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -23,7 +23,7 @@
#include <linux/usb/usbnet.h>
/* datasheet:
- http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf
+ http://ptm2.cc.utu.fi/ftp/network/cards/DM9601/From_NET/DM9601-DS-P01-930914.pdf
*/
/* control requests */
@@ -397,16 +397,24 @@ static void dm9601_set_multicast(struct net_device *net)
dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl);
}
+static void __dm9601_set_mac_address(struct usbnet *dev)
+{
+ dm_write_async(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr);
+}
+
static int dm9601_set_mac_address(struct net_device *net, void *p)
{
struct sockaddr *addr = p;
struct usbnet *dev = netdev_priv(net);
- if (!is_valid_ether_addr(addr->sa_data))
+ if (!is_valid_ether_addr(addr->sa_data)) {
+ dev_err(&net->dev, "not setting invalid mac address %pM\n",
+ addr->sa_data);
return -EINVAL;
+ }
memcpy(net->dev_addr, addr->sa_data, net->addr_len);
- dm_write_async(dev, DM_PHY_ADDR, net->addr_len, net->dev_addr);
+ __dm9601_set_mac_address(dev);
return 0;
}
@@ -414,6 +422,7 @@ static int dm9601_set_mac_address(struct net_device *net, void *p)
static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret;
+ u8 mac[ETH_ALEN];
ret = usbnet_get_endpoints(dev, intf);
if (ret)
@@ -438,12 +447,24 @@ static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
udelay(20);
/* read MAC */
- if (dm_read(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr) < 0) {
+ if (dm_read(dev, DM_PHY_ADDR, ETH_ALEN, mac) < 0) {
printk(KERN_ERR "Error reading MAC address\n");
ret = -ENODEV;
goto out;
}
+ /*
+ * Overwrite the auto-generated address only with good ones.
+ */
+ if (is_valid_ether_addr(mac))
+ memcpy(dev->net->dev_addr, mac, ETH_ALEN);
+ else {
+ printk(KERN_WARNING
+ "dm9601: No valid MAC address in EEPROM, using %pM\n",
+ dev->net->dev_addr);
+ __dm9601_set_mac_address(dev);
+ }
+
/* power up phy */
dm_write_reg(dev, DM_GPR_CTRL, 1);
dm_write_reg(dev, DM_GPR_DATA, 0);
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index c4918b86ed19..0d0fa91c0251 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -1297,6 +1297,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
/* setup */
spin_lock_irq(&serial->serial_lock);
tty->driver_data = serial;
+ tty_kref_put(serial->tty);
serial->tty = tty_kref_get(tty);
spin_unlock_irq(&serial->serial_lock);
@@ -1792,8 +1793,8 @@ static int mux_device_request(struct hso_serial *serial, u8 type, u16 port,
/* initialize */
ctrl_req->wValue = 0;
- ctrl_req->wIndex = hso_port_to_mux(port);
- ctrl_req->wLength = size;
+ ctrl_req->wIndex = cpu_to_le16(hso_port_to_mux(port));
+ ctrl_req->wLength = cpu_to_le16(size);
if (type == USB_CDC_GET_ENCAPSULATED_RESPONSE) {
/* Reading command */
@@ -2043,9 +2044,8 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
return -2;
}
- spin_lock(&serial->serial_lock);
+ /* All callers to put_rxbuf_data hold serial_lock */
tty = tty_kref_get(serial->tty);
- spin_unlock(&serial->serial_lock);
/* Push data to tty */
if (tty) {
@@ -2053,8 +2053,10 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
serial->curr_rx_urb_offset;
D1("data to push to tty");
while (write_length_remaining) {
- if (test_bit(TTY_THROTTLED, &tty->flags))
+ if (test_bit(TTY_THROTTLED, &tty->flags)) {
+ tty_kref_put(tty);
return -1;
+ }
curr_write_len = tty_insert_flip_string
(tty, urb->transfer_buffer +
serial->curr_rx_urb_offset,
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 2ee034f70d1c..7cb10a0a5316 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -251,7 +251,6 @@ struct kaweth_device
struct net_device_stats stats;
};
-
/****************************************************************
* kaweth_control
****************************************************************/
@@ -283,9 +282,9 @@ static int kaweth_control(struct kaweth_device *kaweth,
dr->bRequestType= requesttype;
dr->bRequest = request;
- dr->wValue = cpu_to_le16p(&value);
- dr->wIndex = cpu_to_le16p(&index);
- dr->wLength = cpu_to_le16p(&size);
+ dr->wValue = cpu_to_le16(value);
+ dr->wIndex = cpu_to_le16(index);
+ dr->wLength = cpu_to_le16(size);
return kaweth_internal_control_msg(kaweth->dev,
pipe,
@@ -975,6 +974,17 @@ static int kaweth_resume(struct usb_interface *intf)
/****************************************************************
* kaweth_probe
****************************************************************/
+
+
+static const struct net_device_ops kaweth_netdev_ops = {
+ .ndo_open = kaweth_open,
+ .ndo_stop = kaweth_close,
+ .ndo_start_xmit = kaweth_start_xmit,
+ .ndo_tx_timeout = kaweth_tx_timeout,
+ .ndo_set_multicast_list = kaweth_set_rx_mode,
+ .ndo_get_stats = kaweth_netdev_stats,
+};
+
static int kaweth_probe(
struct usb_interface *intf,
const struct usb_device_id *id /* from id_table */
@@ -1147,22 +1157,13 @@ err_fw:
memcpy(netdev->dev_addr, &kaweth->configuration.hw_addr,
sizeof(kaweth->configuration.hw_addr));
- netdev->open = kaweth_open;
- netdev->stop = kaweth_close;
-
+ netdev->netdev_ops = &kaweth_netdev_ops;
netdev->watchdog_timeo = KAWETH_TX_TIMEOUT;
- netdev->tx_timeout = kaweth_tx_timeout;
-
- netdev->hard_start_xmit = kaweth_start_xmit;
- netdev->set_multicast_list = kaweth_set_rx_mode;
- netdev->get_stats = kaweth_netdev_stats;
netdev->mtu = le16_to_cpu(kaweth->configuration.segment_size);
SET_ETHTOOL_OPS(netdev, &ops);
/* kaweth is zeroed as part of alloc_netdev */
-
INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl);
-
usb_set_intfdata(intf, kaweth);
#if 0
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 166880c113d6..a8228d87c8cf 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -93,6 +93,7 @@ module_param (msg_level, int, 0);
MODULE_PARM_DESC (msg_level, "Override default message level");
MODULE_DEVICE_TABLE(usb, pegasus_ids);
+static const struct net_device_ops pegasus_netdev_ops;
static int update_eth_regs_async(pegasus_t *);
/* Aargh!!! I _really_ hate such tweaks */
@@ -150,8 +151,8 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
pegasus->dr.bRequestType = PEGASUS_REQT_READ;
pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS;
pegasus->dr.wValue = cpu_to_le16(0);
- pegasus->dr.wIndex = cpu_to_le16p(&indx);
- pegasus->dr.wLength = cpu_to_le16p(&size);
+ pegasus->dr.wIndex = cpu_to_le16(indx);
+ pegasus->dr.wLength = cpu_to_le16(size);
pegasus->ctrl_urb->transfer_buffer_length = size;
usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb,
@@ -208,8 +209,8 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS;
pegasus->dr.wValue = cpu_to_le16(0);
- pegasus->dr.wIndex = cpu_to_le16p(&indx);
- pegasus->dr.wLength = cpu_to_le16p(&size);
+ pegasus->dr.wIndex = cpu_to_le16(indx);
+ pegasus->dr.wLength = cpu_to_le16(size);
pegasus->ctrl_urb->transfer_buffer_length = size;
usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb,
@@ -261,7 +262,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
pegasus->dr.bRequest = PEGASUS_REQ_SET_REG;
pegasus->dr.wValue = cpu_to_le16(data);
- pegasus->dr.wIndex = cpu_to_le16p(&indx);
+ pegasus->dr.wIndex = cpu_to_le16(indx);
pegasus->dr.wLength = cpu_to_le16(1);
pegasus->ctrl_urb->transfer_buffer_length = 1;
@@ -476,7 +477,7 @@ static inline void get_node_id(pegasus_t * pegasus, __u8 * id)
for (i = 0; i < 3; i++) {
read_eprom_word(pegasus, i, &w16);
- ((__le16 *) id)[i] = cpu_to_le16p(&w16);
+ ((__le16 *) id)[i] = cpu_to_le16(w16);
}
}
@@ -1360,14 +1361,10 @@ static int pegasus_probe(struct usb_interface *intf,
pegasus->intf = intf;
pegasus->usb = dev;
pegasus->net = net;
- net->open = pegasus_open;
- net->stop = pegasus_close;
+
+
net->watchdog_timeo = PEGASUS_TX_TIMEOUT;
- net->tx_timeout = pegasus_tx_timeout;
- net->do_ioctl = pegasus_ioctl;
- net->hard_start_xmit = pegasus_start_xmit;
- net->set_multicast_list = pegasus_set_multicast;
- net->get_stats = pegasus_netdev_stats;
+ net->netdev_ops = &pegasus_netdev_ops;
SET_ETHTOOL_OPS(net, &ops);
pegasus->mii.dev = net;
pegasus->mii.mdio_read = mdio_read;
@@ -1482,6 +1479,16 @@ static int pegasus_resume (struct usb_interface *intf)
return 0;
}
+static const struct net_device_ops pegasus_netdev_ops = {
+ .ndo_open = pegasus_open,
+ .ndo_stop = pegasus_close,
+ .ndo_do_ioctl = pegasus_ioctl,
+ .ndo_start_xmit = pegasus_start_xmit,
+ .ndo_set_multicast_list = pegasus_set_multicast,
+ .ndo_get_stats = pegasus_netdev_stats,
+ .ndo_tx_timeout = pegasus_tx_timeout,
+};
+
static struct usb_driver pegasus_driver = {
.name = driver_name,
.probe = pegasus_probe,
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index ac07cc6e3cb2..3b8e63254277 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -622,6 +622,7 @@ static const struct net_device_ops rhine_netdev_ops = {
.ndo_get_stats = rhine_get_stats,
.ndo_set_multicast_list = rhine_set_rx_mode,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_do_ioctl = netdev_ioctl,
.ndo_tx_timeout = rhine_tx_timeout,
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 58e25d090ae0..a75f91dc3153 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -855,6 +855,7 @@ static const struct net_device_ops velocity_netdev_ops = {
.ndo_start_xmit = velocity_xmit,
.ndo_get_stats = velocity_get_stats,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_set_multicast_list = velocity_set_multi,
.ndo_change_mtu = velocity_change_mtu,
.ndo_do_ioctl = velocity_ioctl,
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index b7004ff36451..43f6523c40be 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -624,6 +624,18 @@ static int virtnet_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
+static const struct net_device_ops virtnet_netdev = {
+ .ndo_open = virtnet_open,
+ .ndo_stop = virtnet_close,
+ .ndo_start_xmit = start_xmit,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_change_mtu = virtnet_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = virtnet_netpoll,
+#endif
+};
+
static int virtnet_probe(struct virtio_device *vdev)
{
int err;
@@ -636,14 +648,8 @@ static int virtnet_probe(struct virtio_device *vdev)
return -ENOMEM;
/* Set up network device as normal. */
- dev->open = virtnet_open;
- dev->stop = virtnet_close;
- dev->hard_start_xmit = start_xmit;
- dev->change_mtu = virtnet_change_mtu;
+ dev->netdev_ops = &virtnet_netdev;
dev->features = NETIF_F_HIGHDMA;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = virtnet_netpoll;
-#endif
SET_ETHTOOL_OPS(dev, &virtnet_ethtool_ops);
SET_NETDEV_DEV(dev, &vdev->dev);
diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c
index 2dc241689d37..0dbd85b0162d 100644
--- a/drivers/net/wan/ixp4xx_hss.c
+++ b/drivers/net/wan/ixp4xx_hss.c
@@ -622,7 +622,7 @@ static void hss_hdlc_rx_irq(void *pdev)
printk(KERN_DEBUG "%s: hss_hdlc_rx_irq\n", dev->name);
#endif
qmgr_disable_irq(queue_ids[port->id].rx);
- netif_rx_schedule(dev, &port->napi);
+ netif_rx_schedule(&port->napi);
}
static int hss_hdlc_poll(struct napi_struct *napi, int budget)
@@ -651,7 +651,7 @@ static int hss_hdlc_poll(struct napi_struct *napi, int budget)
printk(KERN_DEBUG "%s: hss_hdlc_poll"
" netif_rx_complete\n", dev->name);
#endif
- netif_rx_complete(dev, napi);
+ netif_rx_complete(napi);
qmgr_enable_irq(rxq);
if (!qmgr_stat_empty(rxq) &&
netif_rx_reschedule(napi)) {
@@ -1069,7 +1069,7 @@ static int hss_hdlc_open(struct net_device *dev)
hss_start_hdlc(port);
/* we may already have RX data, enables IRQ */
- netif_rx_schedule(dev, &port->napi);
+ netif_rx_schedule(&port->napi);
return 0;
err_unlock:
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index 3c1edda08d3d..d8322d2d1e29 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -155,6 +155,7 @@ static const struct net_device_ops wd_netdev_ops = {
.ndo_get_stats = ei_get_stats,
.ndo_set_multicast_list = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ei_poll,
diff --git a/drivers/net/wimax/Kconfig b/drivers/net/wimax/Kconfig
new file mode 100644
index 000000000000..565018ec1e3b
--- /dev/null
+++ b/drivers/net/wimax/Kconfig
@@ -0,0 +1,17 @@
+#
+# WiMAX LAN device drivers configuration
+#
+
+
+comment "Enable WiMAX (Networking options) to see the WiMAX drivers"
+ depends on WIMAX = n
+
+if WIMAX
+
+menu "WiMAX Wireless Broadband devices"
+
+source "drivers/net/wimax/i2400m/Kconfig"
+
+endmenu
+
+endif
diff --git a/drivers/net/wimax/Makefile b/drivers/net/wimax/Makefile
new file mode 100644
index 000000000000..992bc02bc016
--- /dev/null
+++ b/drivers/net/wimax/Makefile
@@ -0,0 +1,5 @@
+
+obj-$(CONFIG_WIMAX_I2400M) += i2400m/
+
+# (from Sam Ravnborg) force kbuild to create built-in.o
+obj- := dummy.o
diff --git a/drivers/net/wimax/i2400m/Kconfig b/drivers/net/wimax/i2400m/Kconfig
new file mode 100644
index 000000000000..d623b3d99a4b
--- /dev/null
+++ b/drivers/net/wimax/i2400m/Kconfig
@@ -0,0 +1,49 @@
+
+config WIMAX_I2400M
+ tristate
+ depends on WIMAX
+ select FW_LOADER
+
+comment "Enable USB support to see WiMAX USB drivers"
+ depends on USB = n
+
+comment "Enable MMC support to see WiMAX SDIO drivers"
+ depends on MMC = n
+
+config WIMAX_I2400M_USB
+ tristate "Intel Wireless WiMAX Connection 2400 over USB (including 5x50)"
+ depends on WIMAX && USB
+ select WIMAX_I2400M
+ help
+ Select if you have a device based on the Intel WiMAX
+ Connection 2400 over USB (like any of the Intel Wireless
+ WiMAX/WiFi Link 5x50 series).
+
+ If unsure, it is safe to select M (module).
+
+config WIMAX_I2400M_SDIO
+ tristate "Intel Wireless WiMAX Connection 2400 over SDIO"
+ depends on WIMAX && MMC
+ select WIMAX_I2400M
+ help
+ Select if you have a device based on the Intel WiMAX
+ Connection 2400 over SDIO.
+
+ If unsure, it is safe to select M (module).
+
+config WIMAX_I2400M_DEBUG_LEVEL
+ int "WiMAX i2400m debug level"
+ depends on WIMAX_I2400M
+ default 8
+ help
+
+ Select the maximum debug verbosity level to be compiled into
+ the WiMAX i2400m driver code.
+
+ By default, this is disabled at runtime and can be
+ selectively enabled at runtime for different parts of the
+ code using the sysfs debug-levels file.
+
+ If set at zero, this will compile out all the debug code.
+
+ It is recommended that it is left at 8.
diff --git a/drivers/net/wimax/i2400m/Makefile b/drivers/net/wimax/i2400m/Makefile
new file mode 100644
index 000000000000..1696e936cf5a
--- /dev/null
+++ b/drivers/net/wimax/i2400m/Makefile
@@ -0,0 +1,29 @@
+
+obj-$(CONFIG_WIMAX_I2400M) += i2400m.o
+obj-$(CONFIG_WIMAX_I2400M_USB) += i2400m-usb.o
+obj-$(CONFIG_WIMAX_I2400M_SDIO) += i2400m-sdio.o
+
+i2400m-y := \
+ control.o \
+ driver.o \
+ fw.o \
+ op-rfkill.o \
+ netdev.o \
+ tx.o \
+ rx.o
+
+i2400m-$(CONFIG_DEBUG_FS) += debugfs.o
+
+i2400m-usb-y := \
+ usb-fw.o \
+ usb-notif.o \
+ usb-tx.o \
+ usb-rx.o \
+ usb.o
+
+
+i2400m-sdio-y := \
+ sdio.o \
+ sdio-tx.o \
+ sdio-fw.o \
+ sdio-rx.o
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
new file mode 100644
index 000000000000..d3d37fed6893
--- /dev/null
+++ b/drivers/net/wimax/i2400m/control.c
@@ -0,0 +1,1291 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Miscellaneous control functions for managing the device
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * - Initial implementation
+ *
+ * This is a collection of functions used to control the device (plus
+ * a few helpers).
+ *
+ * There are utilities for handling TLV buffers, hooks on the device's
+ * reports to act on device changes of state [i2400m_report_hook()],
+ * on acks to commands [i2400m_msg_ack_hook()], a helper for sending
+ * commands to the device and blocking until a reply arrives
+ * [i2400m_msg_to_dev()], a few high level commands for manipulating
+ * the device state, powersving mode and configuration plus the
+ * routines to setup the device once communication is stablished with
+ * it [i2400m_dev_initialize()].
+ *
+ * ROADMAP
+ *
+ * i2400m_dev_initalize() Called by i2400m_dev_start()
+ * i2400m_set_init_config()
+ * i2400m_firmware_check()
+ * i2400m_cmd_get_state()
+ * i2400m_dev_shutdown() Called by i2400m_dev_stop()
+ * i2400m->bus_reset()
+ *
+ * i2400m_{cmd,get,set}_*()
+ * i2400m_msg_to_dev()
+ * i2400m_msg_check_status()
+ *
+ * i2400m_report_hook() Called on reception of an event
+ * i2400m_report_state_hook()
+ * i2400m_tlv_buffer_walk()
+ * i2400m_tlv_match()
+ * i2400m_report_tlv_system_state()
+ * i2400m_report_tlv_rf_switches_status()
+ * i2400m_report_tlv_media_status()
+ * i2400m_cmd_enter_powersave()
+ *
+ * i2400m_msg_ack_hook() Called on reception of a reply to a
+ * command, get or set
+ */
+
+#include <stdarg.h>
+#include "i2400m.h"
+#include <linux/kernel.h>
+#include <linux/wimax/i2400m.h>
+
+
+#define D_SUBMODULE control
+#include "debug-levels.h"
+
+
+/*
+ * Return if a TLV is of a give type and size
+ *
+ * @tlv_hdr: pointer to the TLV
+ * @tlv_type: type of the TLV we are looking for
+ * @tlv_size: expected size of the TLV we are looking for (if -1,
+ * don't check the size). This includes the header
+ * Returns: 0 if the TLV matches
+ * < 0 if it doesn't match at all
+ * > 0 total TLV + payload size, if the type matches, but not
+ * the size
+ */
+static
+ssize_t i2400m_tlv_match(const struct i2400m_tlv_hdr *tlv,
+ enum i2400m_tlv tlv_type, ssize_t tlv_size)
+{
+ if (le16_to_cpu(tlv->type) != tlv_type) /* Not our type? skip */
+ return -1;
+ if (tlv_size != -1
+ && le16_to_cpu(tlv->length) + sizeof(*tlv) != tlv_size) {
+ size_t size = le16_to_cpu(tlv->length) + sizeof(*tlv);
+ printk(KERN_WARNING "W: tlv type 0x%x mismatched because of "
+ "size (got %zu vs %zu expected)\n",
+ tlv_type, size, tlv_size);
+ return size;
+ }
+ return 0;
+}
+
+
+/*
+ * Given a buffer of TLVs, iterate over them
+ *
+ * @i2400m: device instance
+ * @tlv_buf: pointer to the beginning of the TLV buffer
+ * @buf_size: buffer size in bytes
+ * @tlv_pos: seek position; this is assumed to be a pointer returned
+ * by i2400m_tlv_buffer_walk() [and thus, validated]. The
+ * TLV returned will be the one following this one.
+ *
+ * Usage:
+ *
+ * tlv_itr = NULL;
+ * while (tlv_itr = i2400m_tlv_buffer_walk(i2400m, buf, size, tlv_itr)) {
+ * ...
+ * // Do stuff with tlv_itr, DON'T MODIFY IT
+ * ...
+ * }
+ */
+static
+const struct i2400m_tlv_hdr *i2400m_tlv_buffer_walk(
+ struct i2400m *i2400m,
+ const void *tlv_buf, size_t buf_size,
+ const struct i2400m_tlv_hdr *tlv_pos)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ const struct i2400m_tlv_hdr *tlv_top = tlv_buf + buf_size;
+ size_t offset, length, avail_size;
+ unsigned type;
+
+ if (tlv_pos == NULL) /* Take the first one? */
+ tlv_pos = tlv_buf;
+ else /* Nope, the next one */
+ tlv_pos = (void *) tlv_pos
+ + le16_to_cpu(tlv_pos->length) + sizeof(*tlv_pos);
+ if (tlv_pos == tlv_top) { /* buffer done */
+ tlv_pos = NULL;
+ goto error_beyond_end;
+ }
+ if (tlv_pos > tlv_top) {
+ tlv_pos = NULL;
+ WARN_ON(1);
+ goto error_beyond_end;
+ }
+ offset = (void *) tlv_pos - (void *) tlv_buf;
+ avail_size = buf_size - offset;
+ if (avail_size < sizeof(*tlv_pos)) {
+ dev_err(dev, "HW BUG? tlv_buf %p [%zu bytes], tlv @%zu: "
+ "short header\n", tlv_buf, buf_size, offset);
+ goto error_short_header;
+ }
+ type = le16_to_cpu(tlv_pos->type);
+ length = le16_to_cpu(tlv_pos->length);
+ if (avail_size < sizeof(*tlv_pos) + length) {
+ dev_err(dev, "HW BUG? tlv_buf %p [%zu bytes], "
+ "tlv type 0x%04x @%zu: "
+ "short data (%zu bytes vs %zu needed)\n",
+ tlv_buf, buf_size, type, offset, avail_size,
+ sizeof(*tlv_pos) + length);
+ goto error_short_header;
+ }
+error_short_header:
+error_beyond_end:
+ return tlv_pos;
+}
+
+
+/*
+ * Find a TLV in a buffer of sequential TLVs
+ *
+ * @i2400m: device descriptor
+ * @tlv_hdr: pointer to the first TLV in the sequence
+ * @size: size of the buffer in bytes; all TLVs are assumed to fit
+ * fully in the buffer (otherwise we'll complain).
+ * @tlv_type: type of the TLV we are looking for
+ * @tlv_size: expected size of the TLV we are looking for (if -1,
+ * don't check the size). This includes the header
+ *
+ * Returns: NULL if the TLV is not found, otherwise a pointer to
+ * it. If the sizes don't match, an error is printed and NULL
+ * returned.
+ */
+static
+const struct i2400m_tlv_hdr *i2400m_tlv_find(
+ struct i2400m *i2400m,
+ const struct i2400m_tlv_hdr *tlv_hdr, size_t size,
+ enum i2400m_tlv tlv_type, ssize_t tlv_size)
+{
+ ssize_t match;
+ struct device *dev = i2400m_dev(i2400m);
+ const struct i2400m_tlv_hdr *tlv = NULL;
+ while ((tlv = i2400m_tlv_buffer_walk(i2400m, tlv_hdr, size, tlv))) {
+ match = i2400m_tlv_match(tlv, tlv_type, tlv_size);
+ if (match == 0) /* found it :) */
+ break;
+ if (match > 0)
+ dev_warn(dev, "TLV type 0x%04x found with size "
+ "mismatch (%zu vs %zu needed)\n",
+ tlv_type, match, tlv_size);
+ }
+ return tlv;
+}
+
+
+static const struct
+{
+ char *msg;
+ int errno;
+} ms_to_errno[I2400M_MS_MAX] = {
+ [I2400M_MS_DONE_OK] = { "", 0 },
+ [I2400M_MS_DONE_IN_PROGRESS] = { "", 0 },
+ [I2400M_MS_INVALID_OP] = { "invalid opcode", -ENOSYS },
+ [I2400M_MS_BAD_STATE] = { "invalid state", -EILSEQ },
+ [I2400M_MS_ILLEGAL_VALUE] = { "illegal value", -EINVAL },
+ [I2400M_MS_MISSING_PARAMS] = { "missing parameters", -ENOMSG },
+ [I2400M_MS_VERSION_ERROR] = { "bad version", -EIO },
+ [I2400M_MS_ACCESSIBILITY_ERROR] = { "accesibility error", -EIO },
+ [I2400M_MS_BUSY] = { "busy", -EBUSY },
+ [I2400M_MS_CORRUPTED_TLV] = { "corrupted TLV", -EILSEQ },
+ [I2400M_MS_UNINITIALIZED] = { "not unitialized", -EILSEQ },
+ [I2400M_MS_UNKNOWN_ERROR] = { "unknown error", -EIO },
+ [I2400M_MS_PRODUCTION_ERROR] = { "production error", -EIO },
+ [I2400M_MS_NO_RF] = { "no RF", -EIO },
+ [I2400M_MS_NOT_READY_FOR_POWERSAVE] =
+ { "not ready for powersave", -EACCES },
+ [I2400M_MS_THERMAL_CRITICAL] = { "thermal critical", -EL3HLT },
+};
+
+
+/*
+ * i2400m_msg_check_status - translate a message's status code
+ *
+ * @i2400m: device descriptor
+ * @l3l4_hdr: message header
+ * @strbuf: buffer to place a formatted error message (unless NULL).
+ * @strbuf_size: max amount of available space; larger messages will
+ * be truncated.
+ *
+ * Returns: errno code corresponding to the status code in @l3l4_hdr
+ * and a message in @strbuf describing the error.
+ */
+int i2400m_msg_check_status(const struct i2400m_l3l4_hdr *l3l4_hdr,
+ char *strbuf, size_t strbuf_size)
+{
+ int result;
+ enum i2400m_ms status = le16_to_cpu(l3l4_hdr->status);
+ const char *str;
+
+ if (status == 0)
+ return 0;
+ if (status > ARRAY_SIZE(ms_to_errno)) {
+ str = "unknown status code";
+ result = -EBADR;
+ } else {
+ str = ms_to_errno[status].msg;
+ result = ms_to_errno[status].errno;
+ }
+ if (strbuf)
+ snprintf(strbuf, strbuf_size, "%s (%d)", str, status);
+ return result;
+}
+
+
+/*
+ * Act on a TLV System State reported by the device
+ *
+ * @i2400m: device descriptor
+ * @ss: validated System State TLV
+ */
+static
+void i2400m_report_tlv_system_state(struct i2400m *i2400m,
+ const struct i2400m_tlv_system_state *ss)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
+ enum i2400m_system_state i2400m_state = le32_to_cpu(ss->state);
+
+ d_fnstart(3, dev, "(i2400m %p ss %p [%u])\n", i2400m, ss, i2400m_state);
+
+ if (unlikely(i2400m->ready == 0)) /* act if up */
+ goto out;
+ if (i2400m->state != i2400m_state) {
+ i2400m->state = i2400m_state;
+ wake_up_all(&i2400m->state_wq);
+ }
+ switch (i2400m_state) {
+ case I2400M_SS_UNINITIALIZED:
+ case I2400M_SS_INIT:
+ case I2400M_SS_CONFIG:
+ case I2400M_SS_PRODUCTION:
+ wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED);
+ break;
+
+ case I2400M_SS_RF_OFF:
+ case I2400M_SS_RF_SHUTDOWN:
+ wimax_state_change(wimax_dev, WIMAX_ST_RADIO_OFF);
+ break;
+
+ case I2400M_SS_READY:
+ case I2400M_SS_STANDBY:
+ case I2400M_SS_SLEEPACTIVE:
+ wimax_state_change(wimax_dev, WIMAX_ST_READY);
+ break;
+
+ case I2400M_SS_CONNECTING:
+ case I2400M_SS_WIMAX_CONNECTED:
+ wimax_state_change(wimax_dev, WIMAX_ST_READY);
+ break;
+
+ case I2400M_SS_SCAN:
+ case I2400M_SS_OUT_OF_ZONE:
+ wimax_state_change(wimax_dev, WIMAX_ST_SCANNING);
+ break;
+
+ case I2400M_SS_IDLE:
+ d_printf(1, dev, "entering BS-negotiated idle mode\n");
+ case I2400M_SS_DISCONNECTING:
+ case I2400M_SS_DATA_PATH_CONNECTED:
+ wimax_state_change(wimax_dev, WIMAX_ST_CONNECTED);
+ break;
+
+ default:
+ /* Huh? just in case, shut it down */
+ dev_err(dev, "HW BUG? unknown state %u: shutting down\n",
+ i2400m_state);
+ i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+ break;
+ };
+out:
+ d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n",
+ i2400m, ss, i2400m_state);
+}
+
+
+/*
+ * Parse and act on a TLV Media Status sent by the device
+ *
+ * @i2400m: device descriptor
+ * @ms: validated Media Status TLV
+ *
+ * This will set the carrier up on down based on the device's link
+ * report. This is done asides of what the WiMAX stack does based on
+ * the device's state as sometimes we need to do a link-renew (the BS
+ * wants us to renew a DHCP lease, for example).
+ *
+ * In fact, doc says that everytime we get a link-up, we should do a
+ * DHCP negotiation...
+ */
+static
+void i2400m_report_tlv_media_status(struct i2400m *i2400m,
+ const struct i2400m_tlv_media_status *ms)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
+ struct net_device *net_dev = wimax_dev->net_dev;
+ enum i2400m_media_status status = le32_to_cpu(ms->media_status);
+
+ d_fnstart(3, dev, "(i2400m %p ms %p [%u])\n", i2400m, ms, status);
+
+ if (unlikely(i2400m->ready == 0)) /* act if up */
+ goto out;
+ switch (status) {
+ case I2400M_MEDIA_STATUS_LINK_UP:
+ netif_carrier_on(net_dev);
+ break;
+ case I2400M_MEDIA_STATUS_LINK_DOWN:
+ netif_carrier_off(net_dev);
+ break;
+ /*
+ * This is the network telling us we need to retrain the DHCP
+ * lease -- so far, we are trusting the WiMAX Network Service
+ * in user space to pick this up and poke the DHCP client.
+ */
+ case I2400M_MEDIA_STATUS_LINK_RENEW:
+ netif_carrier_on(net_dev);
+ break;
+ default:
+ dev_err(dev, "HW BUG? unknown media status %u\n",
+ status);
+ };
+out:
+ d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n",
+ i2400m, ms, status);
+}
+
+
+/*
+ * Parse a 'state report' and extract carrier on/off information
+ *
+ * @i2400m: device descriptor
+ * @l3l4_hdr: pointer to message; it has been already validated for
+ * consistent size.
+ * @size: size of the message (header + payload). The header length
+ * declaration is assumed to be congruent with @size (as in
+ * sizeof(*l3l4_hdr) + l3l4_hdr->length == size)
+ *
+ * Extract from the report state the system state TLV and infer from
+ * there if we have a carrier or not. Update our local state and tell
+ * netdev.
+ *
+ * When setting the carrier, it's fine to set OFF twice (for example),
+ * as netif_carrier_off() will not generate two OFF events (just on
+ * the transitions).
+ */
+static
+void i2400m_report_state_hook(struct i2400m *i2400m,
+ const struct i2400m_l3l4_hdr *l3l4_hdr,
+ size_t size, const char *tag)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ const struct i2400m_tlv_hdr *tlv;
+ const struct i2400m_tlv_system_state *ss;
+ const struct i2400m_tlv_rf_switches_status *rfss;
+ const struct i2400m_tlv_media_status *ms;
+ size_t tlv_size = le16_to_cpu(l3l4_hdr->length);
+
+ d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n",
+ i2400m, l3l4_hdr, size, tag);
+ tlv = NULL;
+
+ while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl,
+ tlv_size, tlv))) {
+ if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE,
+ sizeof(*ss))) {
+ ss = container_of(tlv, typeof(*ss), hdr);
+ d_printf(2, dev, "%s: system state TLV "
+ "found (0x%04x), state 0x%08x\n",
+ tag, I2400M_TLV_SYSTEM_STATE,
+ le32_to_cpu(ss->state));
+ i2400m_report_tlv_system_state(i2400m, ss);
+ }
+ if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS,
+ sizeof(*rfss))) {
+ rfss = container_of(tlv, typeof(*rfss), hdr);
+ d_printf(2, dev, "%s: RF status TLV "
+ "found (0x%04x), sw 0x%02x hw 0x%02x\n",
+ tag, I2400M_TLV_RF_STATUS,
+ le32_to_cpu(rfss->sw_rf_switch),
+ le32_to_cpu(rfss->hw_rf_switch));
+ i2400m_report_tlv_rf_switches_status(i2400m, rfss);
+ }
+ if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS,
+ sizeof(*ms))) {
+ ms = container_of(tlv, typeof(*ms), hdr);
+ d_printf(2, dev, "%s: Media Status TLV: %u\n",
+ tag, le32_to_cpu(ms->media_status));
+ i2400m_report_tlv_media_status(i2400m, ms);
+ }
+ }
+ d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n",
+ i2400m, l3l4_hdr, size, tag);
+}
+
+
+/*
+ * i2400m_report_hook - (maybe) act on a report
+ *
+ * @i2400m: device descriptor
+ * @l3l4_hdr: pointer to message; it has been already validated for
+ * consistent size.
+ * @size: size of the message (header + payload). The header length
+ * declaration is assumed to be congruent with @size (as in
+ * sizeof(*l3l4_hdr) + l3l4_hdr->length == size)
+ *
+ * Extract information we might need (like carrien on/off) from a
+ * device report.
+ */
+void i2400m_report_hook(struct i2400m *i2400m,
+ const struct i2400m_l3l4_hdr *l3l4_hdr, size_t size)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ unsigned msg_type;
+
+ d_fnstart(3, dev, "(i2400m %p l3l4_hdr %p size %zu)\n",
+ i2400m, l3l4_hdr, size);
+ /* Chew on the message, we might need some information from
+ * here */
+ msg_type = le16_to_cpu(l3l4_hdr->type);
+ switch (msg_type) {
+ case I2400M_MT_REPORT_STATE: /* carrier detection... */
+ i2400m_report_state_hook(i2400m,
+ l3l4_hdr, size, "REPORT STATE");
+ break;
+ /* If the device is ready for power save, then ask it to do
+ * it. */
+ case I2400M_MT_REPORT_POWERSAVE_READY: /* zzzzz */
+ if (l3l4_hdr->status == cpu_to_le16(I2400M_MS_DONE_OK)) {
+ d_printf(1, dev, "ready for powersave, requesting\n");
+ i2400m_cmd_enter_powersave(i2400m);
+ }
+ break;
+ };
+ d_fnend(3, dev, "(i2400m %p l3l4_hdr %p size %zu) = void\n",
+ i2400m, l3l4_hdr, size);
+}
+
+
+/*
+ * i2400m_msg_ack_hook - process cmd/set/get ack for internal status
+ *
+ * @i2400m: device descriptor
+ * @l3l4_hdr: pointer to message; it has been already validated for
+ * consistent size.
+ * @size: size of the message
+ *
+ * Extract information we might need from acks to commands and act on
+ * it. This is akin to i2400m_report_hook(). Note most of this
+ * processing should be done in the function that calls the
+ * command. This is here for some cases where it can't happen...
+ */
+void i2400m_msg_ack_hook(struct i2400m *i2400m,
+ const struct i2400m_l3l4_hdr *l3l4_hdr, size_t size)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ unsigned ack_type, ack_status;
+ char strerr[32];
+
+ /* Chew on the message, we might need some information from
+ * here */
+ ack_type = le16_to_cpu(l3l4_hdr->type);
+ ack_status = le16_to_cpu(l3l4_hdr->status);
+ switch (ack_type) {
+ case I2400M_MT_CMD_ENTER_POWERSAVE:
+ /* This is just left here for the sake of example, as
+ * the processing is done somewhere else. */
+ if (0) {
+ result = i2400m_msg_check_status(
+ l3l4_hdr, strerr, sizeof(strerr));
+ if (result >= 0)
+ d_printf(1, dev, "ready for power save: %zd\n",
+ size);
+ }
+ break;
+ };
+ return;
+}
+
+
+/*
+ * i2400m_msg_size_check() - verify message size and header are congruent
+ *
+ * It is ok if the total message size is larger than the expected
+ * size, as there can be padding.
+ */
+int i2400m_msg_size_check(struct i2400m *i2400m,
+ const struct i2400m_l3l4_hdr *l3l4_hdr,
+ size_t msg_size)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ size_t expected_size;
+ d_fnstart(4, dev, "(i2400m %p l3l4_hdr %p msg_size %zu)\n",
+ i2400m, l3l4_hdr, msg_size);
+ if (msg_size < sizeof(*l3l4_hdr)) {
+ dev_err(dev, "bad size for message header "
+ "(expected at least %zu, got %zu)\n",
+ (size_t) sizeof(*l3l4_hdr), msg_size);
+ result = -EIO;
+ goto error_hdr_size;
+ }
+ expected_size = le16_to_cpu(l3l4_hdr->length) + sizeof(*l3l4_hdr);
+ if (msg_size < expected_size) {
+ dev_err(dev, "bad size for message code 0x%04x (expected %zu, "
+ "got %zu)\n", le16_to_cpu(l3l4_hdr->type),
+ expected_size, msg_size);
+ result = -EIO;
+ } else
+ result = 0;
+error_hdr_size:
+ d_fnend(4, dev,
+ "(i2400m %p l3l4_hdr %p msg_size %zu) = %d\n",
+ i2400m, l3l4_hdr, msg_size, result);
+ return result;
+}
+
+
+
+/*
+ * Cancel a wait for a command ACK
+ *
+ * @i2400m: device descriptor
+ * @code: [negative] errno code to cancel with (don't use
+ * -EINPROGRESS)
+ *
+ * If there is an ack already filled out, free it.
+ */
+void i2400m_msg_to_dev_cancel_wait(struct i2400m *i2400m, int code)
+{
+ struct sk_buff *ack_skb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ ack_skb = i2400m->ack_skb;
+ if (ack_skb && !IS_ERR(ack_skb))
+ kfree(ack_skb);
+ i2400m->ack_skb = ERR_PTR(code);
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+}
+
+
+/**
+ * i2400m_msg_to_dev - Send a control message to the device and get a response
+ *
+ * @i2400m: device descriptor
+ *
+ * @msg_skb: an skb *
+ *
+ * @buf: pointer to the buffer containing the message to be sent; it
+ * has to start with a &struct i2400M_l3l4_hdr and then
+ * followed by the payload. Once this function returns, the
+ * buffer can be reused.
+ *
+ * @buf_len: buffer size
+ *
+ * Returns:
+ *
+ * Pointer to skb containing the ack message. You need to check the
+ * pointer with IS_ERR(), as it might be an error code. Error codes
+ * could happen because:
+ *
+ * - the message wasn't formatted correctly
+ * - couldn't send the message
+ * - failed waiting for a response
+ * - the ack message wasn't formatted correctly
+ *
+ * The returned skb has been allocated with wimax_msg_to_user_alloc(),
+ * it contains the reponse in a netlink attribute and is ready to be
+ * passed up to user space with wimax_msg_to_user_send(). To access
+ * the payload and its length, use wimax_msg_{data,len}() on the skb.
+ *
+ * The skb has to be freed with kfree_skb() once done.
+ *
+ * Description:
+ *
+ * This function delivers a message/command to the device and waits
+ * for an ack to be received. The format is described in
+ * linux/wimax/i2400m.h. In summary, a command/get/set is followed by an
+ * ack.
+ *
+ * This function will not check the ack status, that's left up to the
+ * caller. Once done with the ack skb, it has to be kfree_skb()ed.
+ *
+ * The i2400m handles only one message at the same time, thus we need
+ * the mutex to exclude other players.
+ *
+ * We write the message and then wait for an answer to come back. The
+ * RX path intercepts control messages and handles them in
+ * i2400m_rx_ctl(). Reports (notifications) are (maybe) processed
+ * locally and then forwarded (as needed) to user space on the WiMAX
+ * stack message pipe. Acks are saved and passed back to us through an
+ * skb in i2400m->ack_skb which is ready to be given to generic
+ * netlink if need be.
+ */
+struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
+ const void *buf, size_t buf_len)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ const struct i2400m_l3l4_hdr *msg_l3l4_hdr;
+ struct sk_buff *ack_skb;
+ const struct i2400m_l3l4_hdr *ack_l3l4_hdr;
+ size_t ack_len;
+ int ack_timeout;
+ unsigned msg_type;
+ unsigned long flags;
+
+ d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n",
+ i2400m, buf, buf_len);
+
+ if (i2400m->boot_mode)
+ return ERR_PTR(-ENODEV);
+
+ msg_l3l4_hdr = buf;
+ /* Check msg & payload consistency */
+ result = i2400m_msg_size_check(i2400m, msg_l3l4_hdr, buf_len);
+ if (result < 0)
+ goto error_bad_msg;
+ msg_type = le16_to_cpu(msg_l3l4_hdr->type);
+ d_printf(1, dev, "CMD/GET/SET 0x%04x %zu bytes\n",
+ msg_type, buf_len);
+ d_dump(2, dev, buf, buf_len);
+
+ /* Setup the completion, ack_skb ("we are waiting") and send
+ * the message to the device */
+ mutex_lock(&i2400m->msg_mutex);
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ i2400m->ack_skb = ERR_PTR(-EINPROGRESS);
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+ init_completion(&i2400m->msg_completion);
+ result = i2400m_tx(i2400m, buf, buf_len, I2400M_PT_CTRL);
+ if (result < 0) {
+ dev_err(dev, "can't send message 0x%04x: %d\n",
+ le16_to_cpu(msg_l3l4_hdr->type), result);
+ goto error_tx;
+ }
+
+ /* Some commands take longer to execute because of crypto ops,
+ * so we give them some more leeway on timeout */
+ switch (msg_type) {
+ case I2400M_MT_GET_TLS_OPERATION_RESULT:
+ case I2400M_MT_CMD_SEND_EAP_RESPONSE:
+ ack_timeout = 5 * HZ;
+ break;
+ default:
+ ack_timeout = HZ;
+ };
+
+ /* The RX path in rx.c will put any response for this message
+ * in i2400m->ack_skb and wake us up. If we cancel the wait,
+ * we need to change the value of i2400m->ack_skb to something
+ * not -EINPROGRESS so RX knows there is no one waiting. */
+ result = wait_for_completion_interruptible_timeout(
+ &i2400m->msg_completion, ack_timeout);
+ if (result == 0) {
+ dev_err(dev, "timeout waiting for reply to message 0x%04x\n",
+ msg_type);
+ result = -ETIMEDOUT;
+ i2400m_msg_to_dev_cancel_wait(i2400m, result);
+ goto error_wait_for_completion;
+ } else if (result < 0) {
+ dev_err(dev, "error waiting for reply to message 0x%04x: %d\n",
+ msg_type, result);
+ i2400m_msg_to_dev_cancel_wait(i2400m, result);
+ goto error_wait_for_completion;
+ }
+
+ /* Pull out the ack data from i2400m->ack_skb -- see if it is
+ * an error and act accordingly */
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ ack_skb = i2400m->ack_skb;
+ if (IS_ERR(ack_skb))
+ result = PTR_ERR(ack_skb);
+ else
+ result = 0;
+ i2400m->ack_skb = NULL;
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+ if (result < 0)
+ goto error_ack_status;
+ ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len);
+
+ /* Check the ack and deliver it if it is ok */
+ result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len);
+ if (result < 0) {
+ dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n",
+ msg_type, result);
+ goto error_bad_ack_len;
+ }
+ if (msg_type != le16_to_cpu(ack_l3l4_hdr->type)) {
+ dev_err(dev, "HW BUG? bad reply 0x%04x to message 0x%04x\n",
+ le16_to_cpu(ack_l3l4_hdr->type), msg_type);
+ result = -EIO;
+ goto error_bad_ack_type;
+ }
+ i2400m_msg_ack_hook(i2400m, ack_l3l4_hdr, ack_len);
+ mutex_unlock(&i2400m->msg_mutex);
+ d_fnend(3, dev, "(i2400m %p buf %p len %zu) = %p\n",
+ i2400m, buf, buf_len, ack_skb);
+ return ack_skb;
+
+error_bad_ack_type:
+error_bad_ack_len:
+ kfree_skb(ack_skb);
+error_ack_status:
+error_wait_for_completion:
+error_tx:
+ mutex_unlock(&i2400m->msg_mutex);
+error_bad_msg:
+ d_fnend(3, dev, "(i2400m %p buf %p len %zu) = %d\n",
+ i2400m, buf, buf_len, result);
+ return ERR_PTR(result);
+}
+
+
+/*
+ * Definitions for the Enter Power Save command
+ *
+ * The Enter Power Save command requests the device to go into power
+ * saving mode. The device will ack or nak the command depending on it
+ * being ready for it. If it acks, we tell the USB subsystem to
+ *
+ * As well, the device might request to go into power saving mode by
+ * sending a report (REPORT_POWERSAVE_READY), in which case, we issue
+ * this command. The hookups in the RX coder allow
+ */
+enum {
+ I2400M_WAKEUP_ENABLED = 0x01,
+ I2400M_WAKEUP_DISABLED = 0x02,
+ I2400M_TLV_TYPE_WAKEUP_MODE = 144,
+};
+
+struct i2400m_cmd_enter_power_save {
+ struct i2400m_l3l4_hdr hdr;
+ struct i2400m_tlv_hdr tlv;
+ __le32 val;
+} __attribute__((packed));
+
+
+/*
+ * Request entering power save
+ *
+ * This command is (mainly) executed when the device indicates that it
+ * is ready to go into powersave mode via a REPORT_POWERSAVE_READY.
+ */
+int i2400m_cmd_enter_powersave(struct i2400m *i2400m)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct sk_buff *ack_skb;
+ struct i2400m_cmd_enter_power_save *cmd;
+ char strerr[32];
+
+ result = -ENOMEM;
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_alloc;
+ cmd->hdr.type = cpu_to_le16(I2400M_MT_CMD_ENTER_POWERSAVE);
+ cmd->hdr.length = cpu_to_le16(sizeof(*cmd) - sizeof(cmd->hdr));
+ cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION);
+ cmd->tlv.type = cpu_to_le16(I2400M_TLV_TYPE_WAKEUP_MODE);
+ cmd->tlv.length = cpu_to_le16(sizeof(cmd->val));
+ cmd->val = cpu_to_le32(I2400M_WAKEUP_ENABLED);
+
+ ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
+ result = PTR_ERR(ack_skb);
+ if (IS_ERR(ack_skb)) {
+ dev_err(dev, "Failed to issue 'Enter power save' command: %d\n",
+ result);
+ goto error_msg_to_dev;
+ }
+ result = i2400m_msg_check_status(wimax_msg_data(ack_skb),
+ strerr, sizeof(strerr));
+ if (result == -EACCES)
+ d_printf(1, dev, "Cannot enter power save mode\n");
+ else if (result < 0)
+ dev_err(dev, "'Enter power save' (0x%04x) command failed: "
+ "%d - %s\n", I2400M_MT_CMD_ENTER_POWERSAVE,
+ result, strerr);
+ else
+ d_printf(1, dev, "device ready to power save\n");
+ kfree_skb(ack_skb);
+error_msg_to_dev:
+ kfree(cmd);
+error_alloc:
+ return result;
+}
+EXPORT_SYMBOL_GPL(i2400m_cmd_enter_powersave);
+
+
+/*
+ * Definitions for getting device information
+ */
+enum {
+ I2400M_TLV_DETAILED_DEVICE_INFO = 140
+};
+
+/**
+ * i2400m_get_device_info - Query the device for detailed device information
+ *
+ * @i2400m: device descriptor
+ *
+ * Returns: an skb whose skb->data points to a 'struct
+ * i2400m_tlv_detailed_device_info'. When done, kfree_skb() it. The
+ * skb is *guaranteed* to contain the whole TLV data structure.
+ *
+ * On error, IS_ERR(skb) is true and ERR_PTR(skb) is the error
+ * code.
+ */
+struct sk_buff *i2400m_get_device_info(struct i2400m *i2400m)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct sk_buff *ack_skb;
+ struct i2400m_l3l4_hdr *cmd;
+ const struct i2400m_l3l4_hdr *ack;
+ size_t ack_len;
+ const struct i2400m_tlv_hdr *tlv;
+ const struct i2400m_tlv_detailed_device_info *ddi;
+ char strerr[32];
+
+ ack_skb = ERR_PTR(-ENOMEM);
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_alloc;
+ cmd->type = cpu_to_le16(I2400M_MT_GET_DEVICE_INFO);
+ cmd->length = 0;
+ cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
+
+ ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
+ if (IS_ERR(ack_skb)) {
+ dev_err(dev, "Failed to issue 'get device info' command: %ld\n",
+ PTR_ERR(ack_skb));
+ goto error_msg_to_dev;
+ }
+ ack = wimax_msg_data_len(ack_skb, &ack_len);
+ result = i2400m_msg_check_status(ack, strerr, sizeof(strerr));
+ if (result < 0) {
+ dev_err(dev, "'get device info' (0x%04x) command failed: "
+ "%d - %s\n", I2400M_MT_GET_DEVICE_INFO, result,
+ strerr);
+ goto error_cmd_failed;
+ }
+ tlv = i2400m_tlv_find(i2400m, ack->pl, ack_len - sizeof(*ack),
+ I2400M_TLV_DETAILED_DEVICE_INFO, sizeof(*ddi));
+ if (tlv == NULL) {
+ dev_err(dev, "GET DEVICE INFO: "
+ "detailed device info TLV not found (0x%04x)\n",
+ I2400M_TLV_DETAILED_DEVICE_INFO);
+ result = -EIO;
+ goto error_no_tlv;
+ }
+ skb_pull(ack_skb, (void *) tlv - (void *) ack_skb->data);
+error_msg_to_dev:
+ kfree(cmd);
+error_alloc:
+ return ack_skb;
+
+error_no_tlv:
+error_cmd_failed:
+ kfree_skb(ack_skb);
+ kfree(cmd);
+ return ERR_PTR(result);
+}
+
+
+/* Firmware interface versions we support */
+enum {
+ I2400M_HDIv_MAJOR = 9,
+ I2400M_HDIv_MAJOR_2 = 8,
+ I2400M_HDIv_MINOR = 1,
+};
+
+
+/**
+ * i2400m_firmware_check - check firmware versions are compatible with
+ * the driver
+ *
+ * @i2400m: device descriptor
+ *
+ * Returns: 0 if ok, < 0 errno code an error and a message in the
+ * kernel log.
+ *
+ * Long function, but quite simple; first chunk launches the command
+ * and double checks the reply for the right TLV. Then we process the
+ * TLV (where the meat is).
+ */
+int i2400m_firmware_check(struct i2400m *i2400m)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct sk_buff *ack_skb;
+ struct i2400m_l3l4_hdr *cmd;
+ const struct i2400m_l3l4_hdr *ack;
+ size_t ack_len;
+ const struct i2400m_tlv_hdr *tlv;
+ const struct i2400m_tlv_l4_message_versions *l4mv;
+ char strerr[32];
+ unsigned major, minor, branch;
+
+ result = -ENOMEM;
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_alloc;
+ cmd->type = cpu_to_le16(I2400M_MT_GET_LM_VERSION);
+ cmd->length = 0;
+ cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
+
+ ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
+ if (IS_ERR(ack_skb)) {
+ result = PTR_ERR(ack_skb);
+ dev_err(dev, "Failed to issue 'get lm version' command: %-d\n",
+ result);
+ goto error_msg_to_dev;
+ }
+ ack = wimax_msg_data_len(ack_skb, &ack_len);
+ result = i2400m_msg_check_status(ack, strerr, sizeof(strerr));
+ if (result < 0) {
+ dev_err(dev, "'get lm version' (0x%04x) command failed: "
+ "%d - %s\n", I2400M_MT_GET_LM_VERSION, result,
+ strerr);
+ goto error_cmd_failed;
+ }
+ tlv = i2400m_tlv_find(i2400m, ack->pl, ack_len - sizeof(*ack),
+ I2400M_TLV_L4_MESSAGE_VERSIONS, sizeof(*l4mv));
+ if (tlv == NULL) {
+ dev_err(dev, "get lm version: TLV not found (0x%04x)\n",
+ I2400M_TLV_L4_MESSAGE_VERSIONS);
+ result = -EIO;
+ goto error_no_tlv;
+ }
+ l4mv = container_of(tlv, typeof(*l4mv), hdr);
+ major = le16_to_cpu(l4mv->major);
+ minor = le16_to_cpu(l4mv->minor);
+ branch = le16_to_cpu(l4mv->branch);
+ result = -EINVAL;
+ if (major != I2400M_HDIv_MAJOR
+ && major != I2400M_HDIv_MAJOR_2) {
+ dev_err(dev, "unsupported major fw interface version "
+ "%u.%u.%u\n", major, minor, branch);
+ goto error_bad_major;
+ }
+ if (major == I2400M_HDIv_MAJOR_2)
+ dev_err(dev, "deprecated major fw interface version "
+ "%u.%u.%u\n", major, minor, branch);
+ result = 0;
+ if (minor != I2400M_HDIv_MINOR)
+ dev_warn(dev, "untested minor fw firmware version %u.%u.%u\n",
+ major, minor, branch);
+error_bad_major:
+ dev_info(dev, "firmware interface version %u.%u.%u\n",
+ major, minor, branch);
+error_no_tlv:
+error_cmd_failed:
+ kfree_skb(ack_skb);
+error_msg_to_dev:
+ kfree(cmd);
+error_alloc:
+ return result;
+}
+
+
+/*
+ * Send an DoExitIdle command to the device to ask it to go out of
+ * basestation-idle mode.
+ *
+ * @i2400m: device descriptor
+ *
+ * This starts a renegotiation with the basestation that might involve
+ * another crypto handshake with user space.
+ *
+ * Returns: 0 if ok, < 0 errno code on error.
+ */
+int i2400m_cmd_exit_idle(struct i2400m *i2400m)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct sk_buff *ack_skb;
+ struct i2400m_l3l4_hdr *cmd;
+ char strerr[32];
+
+ result = -ENOMEM;
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_alloc;
+ cmd->type = cpu_to_le16(I2400M_MT_CMD_EXIT_IDLE);
+ cmd->length = 0;
+ cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
+
+ ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
+ result = PTR_ERR(ack_skb);
+ if (IS_ERR(ack_skb)) {
+ dev_err(dev, "Failed to issue 'exit idle' command: %d\n",
+ result);
+ goto error_msg_to_dev;
+ }
+ result = i2400m_msg_check_status(wimax_msg_data(ack_skb),
+ strerr, sizeof(strerr));
+ kfree_skb(ack_skb);
+error_msg_to_dev:
+ kfree(cmd);
+error_alloc:
+ return result;
+
+}
+
+
+/*
+ * Query the device for its state, update the WiMAX stack's idea of it
+ *
+ * @i2400m: device descriptor
+ *
+ * Returns: 0 if ok, < 0 errno code on error.
+ *
+ * Executes a 'Get State' command and parses the returned
+ * TLVs.
+ *
+ * Because this is almost identical to a 'Report State', we use
+ * i2400m_report_state_hook() to parse the answer. This will set the
+ * carrier state, as well as the RF Kill switches state.
+ */
+int i2400m_cmd_get_state(struct i2400m *i2400m)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct sk_buff *ack_skb;
+ struct i2400m_l3l4_hdr *cmd;
+ const struct i2400m_l3l4_hdr *ack;
+ size_t ack_len;
+ char strerr[32];
+
+ result = -ENOMEM;
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_alloc;
+ cmd->type = cpu_to_le16(I2400M_MT_GET_STATE);
+ cmd->length = 0;
+ cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
+
+ ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
+ if (IS_ERR(ack_skb)) {
+ dev_err(dev, "Failed to issue 'get state' command: %ld\n",
+ PTR_ERR(ack_skb));
+ result = PTR_ERR(ack_skb);
+ goto error_msg_to_dev;
+ }
+ ack = wimax_msg_data_len(ack_skb, &ack_len);
+ result = i2400m_msg_check_status(ack, strerr, sizeof(strerr));
+ if (result < 0) {
+ dev_err(dev, "'get state' (0x%04x) command failed: "
+ "%d - %s\n", I2400M_MT_GET_STATE, result, strerr);
+ goto error_cmd_failed;
+ }
+ i2400m_report_state_hook(i2400m, ack, ack_len - sizeof(*ack),
+ "GET STATE");
+ result = 0;
+ kfree_skb(ack_skb);
+error_cmd_failed:
+error_msg_to_dev:
+ kfree(cmd);
+error_alloc:
+ return result;
+}
+EXPORT_SYMBOL_GPL(i2400m_cmd_get_state);
+
+
+/**
+ * Set basic configuration settings
+ *
+ * @i2400m: device descriptor
+ * @args: array of pointers to the TLV headers to send for
+ * configuration (each followed by its payload).
+ * TLV headers and payloads must be properly initialized, with the
+ * right endianess (LE).
+ * @arg_size: number of pointers in the @args array
+ */
+int i2400m_set_init_config(struct i2400m *i2400m,
+ const struct i2400m_tlv_hdr **arg, size_t args)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct sk_buff *ack_skb;
+ struct i2400m_l3l4_hdr *cmd;
+ char strerr[32];
+ unsigned argc, argsize, tlv_size;
+ const struct i2400m_tlv_hdr *tlv_hdr;
+ void *buf, *itr;
+
+ d_fnstart(3, dev, "(i2400m %p arg %p args %zu)\n", i2400m, arg, args);
+ result = 0;
+ if (args == 0)
+ goto none;
+ /* Compute the size of all the TLVs, so we can alloc a
+ * contiguous command block to copy them. */
+ argsize = 0;
+ for (argc = 0; argc < args; argc++) {
+ tlv_hdr = arg[argc];
+ argsize += sizeof(*tlv_hdr) + le16_to_cpu(tlv_hdr->length);
+ }
+ WARN_ON(argc >= 9); /* As per hw spec */
+
+ /* Alloc the space for the command and TLVs*/
+ result = -ENOMEM;
+ buf = kzalloc(sizeof(*cmd) + argsize, GFP_KERNEL);
+ if (buf == NULL)
+ goto error_alloc;
+ cmd = buf;
+ cmd->type = cpu_to_le16(I2400M_MT_SET_INIT_CONFIG);
+ cmd->length = cpu_to_le16(argsize);
+ cmd->version = cpu_to_le16(I2400M_L3L4_VERSION);
+
+ /* Copy the TLVs */
+ itr = buf + sizeof(*cmd);
+ for (argc = 0; argc < args; argc++) {
+ tlv_hdr = arg[argc];
+ tlv_size = sizeof(*tlv_hdr) + le16_to_cpu(tlv_hdr->length);
+ memcpy(itr, tlv_hdr, tlv_size);
+ itr += tlv_size;
+ }
+
+ /* Send the message! */
+ ack_skb = i2400m_msg_to_dev(i2400m, buf, sizeof(*cmd) + argsize);
+ result = PTR_ERR(ack_skb);
+ if (IS_ERR(ack_skb)) {
+ dev_err(dev, "Failed to issue 'init config' command: %d\n",
+ result);
+
+ goto error_msg_to_dev;
+ }
+ result = i2400m_msg_check_status(wimax_msg_data(ack_skb),
+ strerr, sizeof(strerr));
+ if (result < 0)
+ dev_err(dev, "'init config' (0x%04x) command failed: %d - %s\n",
+ I2400M_MT_SET_INIT_CONFIG, result, strerr);
+ kfree_skb(ack_skb);
+error_msg_to_dev:
+ kfree(buf);
+error_alloc:
+none:
+ d_fnend(3, dev, "(i2400m %p arg %p args %zu) = %d\n",
+ i2400m, arg, args, result);
+ return result;
+
+}
+EXPORT_SYMBOL_GPL(i2400m_set_init_config);
+
+
+/**
+ * i2400m_dev_initialize - Initialize the device once communications are ready
+ *
+ * @i2400m: device descriptor
+ *
+ * Returns: 0 if ok, < 0 errno code on error.
+ *
+ * Configures the device to work the way we like it.
+ *
+ * At the point of this call, the device is registered with the WiMAX
+ * and netdev stacks, firmware is uploaded and we can talk to the
+ * device normally.
+ */
+int i2400m_dev_initialize(struct i2400m *i2400m)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct i2400m_tlv_config_idle_parameters idle_params;
+ const struct i2400m_tlv_hdr *args[9];
+ unsigned argc = 0;
+
+ d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+ /* Useless for now...might change */
+ if (i2400m_idle_mode_disabled) {
+ idle_params.hdr.type =
+ cpu_to_le16(I2400M_TLV_CONFIG_IDLE_PARAMETERS);
+ idle_params.hdr.length = cpu_to_le16(
+ sizeof(idle_params) - sizeof(idle_params.hdr));
+ idle_params.idle_timeout = 0;
+ idle_params.idle_paging_interval = 0;
+ args[argc++] = &idle_params.hdr;
+ }
+ result = i2400m_set_init_config(i2400m, args, argc);
+ if (result < 0)
+ goto error;
+ result = i2400m_firmware_check(i2400m); /* fw versions ok? */
+ if (result < 0)
+ goto error;
+ /*
+ * Update state: Here it just calls a get state; parsing the
+ * result (System State TLV and RF Status TLV [done in the rx
+ * path hooks]) will set the hardware and software RF-Kill
+ * status.
+ */
+ result = i2400m_cmd_get_state(i2400m);
+error:
+ d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
+ return result;
+}
+
+
+/**
+ * i2400m_dev_shutdown - Shutdown a running device
+ *
+ * @i2400m: device descriptor
+ *
+ * Gracefully stops the device, moving it to the lowest power
+ * consumption state possible.
+ */
+void i2400m_dev_shutdown(struct i2400m *i2400m)
+{
+ int result = -ENODEV;
+ struct device *dev = i2400m_dev(i2400m);
+
+ d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+ result = i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+ d_fnend(3, dev, "(i2400m %p) = void [%d]\n", i2400m, result);
+ return;
+}
diff --git a/drivers/net/wimax/i2400m/debug-levels.h b/drivers/net/wimax/i2400m/debug-levels.h
new file mode 100644
index 000000000000..3183baa16a52
--- /dev/null
+++ b/drivers/net/wimax/i2400m/debug-levels.h
@@ -0,0 +1,45 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Debug levels control file for the i2400m module
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This 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.
+ */
+#ifndef __debug_levels__h__
+#define __debug_levels__h__
+
+/* Maximum compile and run time debug level for all submodules */
+#define D_MODULENAME i2400m
+#define D_MASTER CONFIG_WIMAX_I2400M_DEBUG_LEVEL
+
+#include <linux/wimax/debug.h>
+
+/* List of all the enabled modules */
+enum d_module {
+ D_SUBMODULE_DECLARE(control),
+ D_SUBMODULE_DECLARE(driver),
+ D_SUBMODULE_DECLARE(debugfs),
+ D_SUBMODULE_DECLARE(fw),
+ D_SUBMODULE_DECLARE(netdev),
+ D_SUBMODULE_DECLARE(rfkill),
+ D_SUBMODULE_DECLARE(rx),
+ D_SUBMODULE_DECLARE(tx),
+};
+
+
+#endif /* #ifndef __debug_levels__h__ */
diff --git a/drivers/net/wimax/i2400m/debugfs.c b/drivers/net/wimax/i2400m/debugfs.c
new file mode 100644
index 000000000000..626632985977
--- /dev/null
+++ b/drivers/net/wimax/i2400m/debugfs.c
@@ -0,0 +1,392 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Debugfs interfaces to manipulate driver and device information
+ *
+ *
+ * Copyright (C) 2007 Intel Corporation <linux-wimax@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This 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/debugfs.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include "i2400m.h"
+
+
+#define D_SUBMODULE debugfs
+#include "debug-levels.h"
+
+static
+int debugfs_netdev_queue_stopped_get(void *data, u64 *val)
+{
+ struct i2400m *i2400m = data;
+ *val = netif_queue_stopped(i2400m->wimax_dev.net_dev);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_netdev_queue_stopped,
+ debugfs_netdev_queue_stopped_get,
+ NULL, "%llu\n");
+
+
+static
+struct dentry *debugfs_create_netdev_queue_stopped(
+ const char *name, struct dentry *parent, struct i2400m *i2400m)
+{
+ return debugfs_create_file(name, 0400, parent, i2400m,
+ &fops_netdev_queue_stopped);
+}
+
+
+/*
+ * inode->i_private has the @data argument to debugfs_create_file()
+ */
+static
+int i2400m_stats_open(struct inode *inode, struct file *filp)
+{
+ filp->private_data = inode->i_private;
+ return 0;
+}
+
+/*
+ * We don't allow partial reads of this file, as then the reader would
+ * get weirdly confused data as it is updated.
+ *
+ * So or you read it all or nothing; if you try to read with an offset
+ * != 0, we consider you are done reading.
+ */
+static
+ssize_t i2400m_rx_stats_read(struct file *filp, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct i2400m *i2400m = filp->private_data;
+ char buf[128];
+ unsigned long flags;
+
+ if (*ppos != 0)
+ return 0;
+ if (count < sizeof(buf))
+ return -ENOSPC;
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ snprintf(buf, sizeof(buf), "%u %u %u %u %u %u %u\n",
+ i2400m->rx_pl_num, i2400m->rx_pl_min,
+ i2400m->rx_pl_max, i2400m->rx_num,
+ i2400m->rx_size_acc,
+ i2400m->rx_size_min, i2400m->rx_size_max);
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+ return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+}
+
+
+/* Any write clears the stats */
+static
+ssize_t i2400m_rx_stats_write(struct file *filp, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct i2400m *i2400m = filp->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ i2400m->rx_pl_num = 0;
+ i2400m->rx_pl_max = 0;
+ i2400m->rx_pl_min = UINT_MAX;
+ i2400m->rx_num = 0;
+ i2400m->rx_size_acc = 0;
+ i2400m->rx_size_min = UINT_MAX;
+ i2400m->rx_size_max = 0;
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+ return count;
+}
+
+static
+const struct file_operations i2400m_rx_stats_fops = {
+ .owner = THIS_MODULE,
+ .open = i2400m_stats_open,
+ .read = i2400m_rx_stats_read,
+ .write = i2400m_rx_stats_write,
+};
+
+
+/* See i2400m_rx_stats_read() */
+static
+ssize_t i2400m_tx_stats_read(struct file *filp, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct i2400m *i2400m = filp->private_data;
+ char buf[128];
+ unsigned long flags;
+
+ if (*ppos != 0)
+ return 0;
+ if (count < sizeof(buf))
+ return -ENOSPC;
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
+ snprintf(buf, sizeof(buf), "%u %u %u %u %u %u %u\n",
+ i2400m->tx_pl_num, i2400m->tx_pl_min,
+ i2400m->tx_pl_max, i2400m->tx_num,
+ i2400m->tx_size_acc,
+ i2400m->tx_size_min, i2400m->tx_size_max);
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+ return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
+}
+
+/* Any write clears the stats */
+static
+ssize_t i2400m_tx_stats_write(struct file *filp, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct i2400m *i2400m = filp->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
+ i2400m->tx_pl_num = 0;
+ i2400m->tx_pl_max = 0;
+ i2400m->tx_pl_min = UINT_MAX;
+ i2400m->tx_num = 0;
+ i2400m->tx_size_acc = 0;
+ i2400m->tx_size_min = UINT_MAX;
+ i2400m->tx_size_max = 0;
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+ return count;
+}
+
+static
+const struct file_operations i2400m_tx_stats_fops = {
+ .owner = THIS_MODULE,
+ .open = i2400m_stats_open,
+ .read = i2400m_tx_stats_read,
+ .write = i2400m_tx_stats_write,
+};
+
+
+/* Write 1 to ask the device to go into suspend */
+static
+int debugfs_i2400m_suspend_set(void *data, u64 val)
+{
+ int result;
+ struct i2400m *i2400m = data;
+ result = i2400m_cmd_enter_powersave(i2400m);
+ if (result >= 0)
+ result = 0;
+ return result;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_i2400m_suspend,
+ NULL, debugfs_i2400m_suspend_set,
+ "%llu\n");
+
+static
+struct dentry *debugfs_create_i2400m_suspend(
+ const char *name, struct dentry *parent, struct i2400m *i2400m)
+{
+ return debugfs_create_file(name, 0200, parent, i2400m,
+ &fops_i2400m_suspend);
+}
+
+
+/*
+ * Reset the device
+ *
+ * Write 0 to ask the device to soft reset, 1 to cold reset, 2 to bus
+ * reset (as defined by enum i2400m_reset_type).
+ */
+static
+int debugfs_i2400m_reset_set(void *data, u64 val)
+{
+ int result;
+ struct i2400m *i2400m = data;
+ enum i2400m_reset_type rt = val;
+ switch(rt) {
+ case I2400M_RT_WARM:
+ case I2400M_RT_COLD:
+ case I2400M_RT_BUS:
+ result = i2400m->bus_reset(i2400m, rt);
+ if (result >= 0)
+ result = 0;
+ default:
+ result = -EINVAL;
+ }
+ return result;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_i2400m_reset,
+ NULL, debugfs_i2400m_reset_set,
+ "%llu\n");
+
+static
+struct dentry *debugfs_create_i2400m_reset(
+ const char *name, struct dentry *parent, struct i2400m *i2400m)
+{
+ return debugfs_create_file(name, 0200, parent, i2400m,
+ &fops_i2400m_reset);
+}
+
+/*
+ * Debug levels control; see debug.h
+ */
+struct d_level D_LEVEL[] = {
+ D_SUBMODULE_DEFINE(control),
+ D_SUBMODULE_DEFINE(driver),
+ D_SUBMODULE_DEFINE(debugfs),
+ D_SUBMODULE_DEFINE(fw),
+ D_SUBMODULE_DEFINE(netdev),
+ D_SUBMODULE_DEFINE(rfkill),
+ D_SUBMODULE_DEFINE(rx),
+ D_SUBMODULE_DEFINE(tx),
+};
+size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
+
+#define __debugfs_register(prefix, name, parent) \
+do { \
+ result = d_level_register_debugfs(prefix, name, parent); \
+ if (result < 0) \
+ goto error; \
+} while (0)
+
+
+int i2400m_debugfs_add(struct i2400m *i2400m)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct dentry *dentry = i2400m->wimax_dev.debugfs_dentry;
+ struct dentry *fd;
+
+ dentry = debugfs_create_dir("i2400m", dentry);
+ result = PTR_ERR(dentry);
+ if (IS_ERR(dentry)) {
+ if (result == -ENODEV)
+ result = 0; /* No debugfs support */
+ goto error;
+ }
+ i2400m->debugfs_dentry = dentry;
+ __debugfs_register("dl_", control, dentry);
+ __debugfs_register("dl_", driver, dentry);
+ __debugfs_register("dl_", debugfs, dentry);
+ __debugfs_register("dl_", fw, dentry);
+ __debugfs_register("dl_", netdev, dentry);
+ __debugfs_register("dl_", rfkill, dentry);
+ __debugfs_register("dl_", rx, dentry);
+ __debugfs_register("dl_", tx, dentry);
+
+ fd = debugfs_create_size_t("tx_in", 0400, dentry,
+ &i2400m->tx_in);
+ result = PTR_ERR(fd);
+ if (IS_ERR(fd) && result != -ENODEV) {
+ dev_err(dev, "Can't create debugfs entry "
+ "tx_in: %d\n", result);
+ goto error;
+ }
+
+ fd = debugfs_create_size_t("tx_out", 0400, dentry,
+ &i2400m->tx_out);
+ result = PTR_ERR(fd);
+ if (IS_ERR(fd) && result != -ENODEV) {
+ dev_err(dev, "Can't create debugfs entry "
+ "tx_out: %d\n", result);
+ goto error;
+ }
+
+ fd = debugfs_create_u32("state", 0600, dentry,
+ &i2400m->state);
+ result = PTR_ERR(fd);
+ if (IS_ERR(fd) && result != -ENODEV) {
+ dev_err(dev, "Can't create debugfs entry "
+ "state: %d\n", result);
+ goto error;
+ }
+
+ /*
+ * Trace received messages from user space
+ *
+ * In order to tap the bidirectional message stream in the
+ * 'msg' pipe, user space can read from the 'msg' pipe;
+ * however, due to limitations in libnl, we can't know what
+ * the different applications are sending down to the kernel.
+ *
+ * So we have this hack where the driver will echo any message
+ * received on the msg pipe from user space [through a call to
+ * wimax_dev->op_msg_from_user() into
+ * i2400m_op_msg_from_user()] into the 'trace' pipe that this
+ * driver creates.
+ *
+ * So then, reading from both the 'trace' and 'msg' pipes in
+ * user space will provide a full dump of the traffic.
+ *
+ * Write 1 to activate, 0 to clear.
+ *
+ * It is not really very atomic, but it is also not too
+ * critical.
+ */
+ fd = debugfs_create_u8("trace_msg_from_user", 0600, dentry,
+ &i2400m->trace_msg_from_user);
+ result = PTR_ERR(fd);
+ if (IS_ERR(fd) && result != -ENODEV) {
+ dev_err(dev, "Can't create debugfs entry "
+ "trace_msg_from_user: %d\n", result);
+ goto error;
+ }
+
+ fd = debugfs_create_netdev_queue_stopped("netdev_queue_stopped",
+ dentry, i2400m);
+ result = PTR_ERR(fd);
+ if (IS_ERR(fd) && result != -ENODEV) {
+ dev_err(dev, "Can't create debugfs entry "
+ "netdev_queue_stopped: %d\n", result);
+ goto error;
+ }
+
+ fd = debugfs_create_file("rx_stats", 0600, dentry, i2400m,
+ &i2400m_rx_stats_fops);
+ result = PTR_ERR(fd);
+ if (IS_ERR(fd) && result != -ENODEV) {
+ dev_err(dev, "Can't create debugfs entry "
+ "rx_stats: %d\n", result);
+ goto error;
+ }
+
+ fd = debugfs_create_file("tx_stats", 0600, dentry, i2400m,
+ &i2400m_tx_stats_fops);
+ result = PTR_ERR(fd);
+ if (IS_ERR(fd) && result != -ENODEV) {
+ dev_err(dev, "Can't create debugfs entry "
+ "tx_stats: %d\n", result);
+ goto error;
+ }
+
+ fd = debugfs_create_i2400m_suspend("suspend", dentry, i2400m);
+ result = PTR_ERR(fd);
+ if (IS_ERR(fd) && result != -ENODEV) {
+ dev_err(dev, "Can't create debugfs entry suspend: %d\n",
+ result);
+ goto error;
+ }
+
+ fd = debugfs_create_i2400m_reset("reset", dentry, i2400m);
+ result = PTR_ERR(fd);
+ if (IS_ERR(fd) && result != -ENODEV) {
+ dev_err(dev, "Can't create debugfs entry reset: %d\n", result);
+ goto error;
+ }
+
+ result = 0;
+error:
+ return result;
+}
+
+void i2400m_debugfs_rm(struct i2400m *i2400m)
+{
+ debugfs_remove_recursive(i2400m->debugfs_dentry);
+}
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
new file mode 100644
index 000000000000..5f98047e18cf
--- /dev/null
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -0,0 +1,728 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Generic probe/disconnect, reset and message passing
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This 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.
+ *
+ *
+ * See i2400m.h for driver documentation. This contains helpers for
+ * the driver model glue [_setup()/_release()], handling device resets
+ * [_dev_reset_handle()], and the backends for the WiMAX stack ops
+ * reset [_op_reset()] and message from user [_op_msg_from_user()].
+ *
+ * ROADMAP:
+ *
+ * i2400m_op_msg_from_user()
+ * i2400m_msg_to_dev()
+ * wimax_msg_to_user_send()
+ *
+ * i2400m_op_reset()
+ * i240m->bus_reset()
+ *
+ * i2400m_dev_reset_handle()
+ * __i2400m_dev_reset_handle()
+ * __i2400m_dev_stop()
+ * __i2400m_dev_start()
+ *
+ * i2400m_setup()
+ * i2400m_bootrom_init()
+ * register_netdev()
+ * i2400m_dev_start()
+ * __i2400m_dev_start()
+ * i2400m_dev_bootstrap()
+ * i2400m_tx_setup()
+ * i2400m->bus_dev_start()
+ * i2400m_check_mac_addr()
+ * wimax_dev_add()
+ *
+ * i2400m_release()
+ * wimax_dev_rm()
+ * i2400m_dev_stop()
+ * __i2400m_dev_stop()
+ * i2400m_dev_shutdown()
+ * i2400m->bus_dev_stop()
+ * i2400m_tx_release()
+ * unregister_netdev()
+ */
+#include "i2400m.h"
+#include <linux/wimax/i2400m.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#define D_SUBMODULE driver
+#include "debug-levels.h"
+
+
+int i2400m_idle_mode_disabled; /* 0 (idle mode enabled) by default */
+module_param_named(idle_mode_disabled, i2400m_idle_mode_disabled, int, 0644);
+MODULE_PARM_DESC(idle_mode_disabled,
+ "If true, the device will not enable idle mode negotiation "
+ "with the base station (when connected) to save power.");
+
+/**
+ * i2400m_queue_work - schedule work on a i2400m's queue
+ *
+ * @i2400m: device descriptor
+ *
+ * @fn: function to run to execute work. It gets passed a 'struct
+ * work_struct' that is wrapped in a 'struct i2400m_work'. Once
+ * done, you have to (1) i2400m_put(i2400m_work->i2400m) and then
+ * (2) kfree(i2400m_work).
+ *
+ * @gfp_flags: GFP flags for memory allocation.
+ *
+ * @pl: pointer to a payload buffer that you want to pass to the _work
+ * function. Use this to pack (for example) a struct with extra
+ * arguments.
+ *
+ * @pl_size: size of the payload buffer.
+ *
+ * We do this quite often, so this just saves typing; allocate a
+ * wrapper for a i2400m, get a ref to it, pack arguments and launch
+ * the work.
+ *
+ * A usual workflow is:
+ *
+ * struct my_work_args {
+ * void *something;
+ * int whatever;
+ * };
+ * ...
+ *
+ * struct my_work_args my_args = {
+ * .something = FOO,
+ * .whaetever = BLAH
+ * };
+ * i2400m_queue_work(i2400m, 1, my_work_function, GFP_KERNEL,
+ * &args, sizeof(args))
+ *
+ * And now the work function can unpack the arguments and call the
+ * real function (or do the job itself):
+ *
+ * static
+ * void my_work_fn((struct work_struct *ws)
+ * {
+ * struct i2400m_work *iw =
+ * container_of(ws, struct i2400m_work, ws);
+ * struct my_work_args *my_args = (void *) iw->pl;
+ *
+ * my_work(iw->i2400m, my_args->something, my_args->whatevert);
+ * }
+ */
+int i2400m_queue_work(struct i2400m *i2400m,
+ void (*fn)(struct work_struct *), gfp_t gfp_flags,
+ const void *pl, size_t pl_size)
+{
+ int result;
+ struct i2400m_work *iw;
+
+ BUG_ON(i2400m->work_queue == NULL);
+ result = -ENOMEM;
+ iw = kzalloc(sizeof(*iw) + pl_size, gfp_flags);
+ if (iw == NULL)
+ goto error_kzalloc;
+ iw->i2400m = i2400m_get(i2400m);
+ memcpy(iw->pl, pl, pl_size);
+ INIT_WORK(&iw->ws, fn);
+ result = queue_work(i2400m->work_queue, &iw->ws);
+error_kzalloc:
+ return result;
+}
+EXPORT_SYMBOL_GPL(i2400m_queue_work);
+
+
+/*
+ * Schedule i2400m's specific work on the system's queue.
+ *
+ * Used for a few cases where we really need it; otherwise, identical
+ * to i2400m_queue_work().
+ *
+ * Returns < 0 errno code on error, 1 if ok.
+ *
+ * If it returns zero, something really bad happened, as it means the
+ * works struct was already queued, but we have just allocated it, so
+ * it should not happen.
+ */
+int i2400m_schedule_work(struct i2400m *i2400m,
+ void (*fn)(struct work_struct *), gfp_t gfp_flags)
+{
+ int result;
+ struct i2400m_work *iw;
+
+ BUG_ON(i2400m->work_queue == NULL);
+ result = -ENOMEM;
+ iw = kzalloc(sizeof(*iw), gfp_flags);
+ if (iw == NULL)
+ goto error_kzalloc;
+ iw->i2400m = i2400m_get(i2400m);
+ INIT_WORK(&iw->ws, fn);
+ result = schedule_work(&iw->ws);
+ if (result == 0)
+ result = -ENXIO;
+error_kzalloc:
+ return result;
+}
+
+
+/*
+ * WiMAX stack operation: relay a message from user space
+ *
+ * @wimax_dev: device descriptor
+ * @pipe_name: named pipe the message is for
+ * @msg_buf: pointer to the message bytes
+ * @msg_len: length of the buffer
+ * @genl_info: passed by the generic netlink layer
+ *
+ * The WiMAX stack will call this function when a message was received
+ * from user space.
+ *
+ * For the i2400m, this is an L3L4 message, as specified in
+ * include/linux/wimax/i2400m.h, and thus prefixed with a 'struct
+ * i2400m_l3l4_hdr'. Driver (and device) expect the messages to be
+ * coded in Little Endian.
+ *
+ * This function just verifies that the header declaration and the
+ * payload are consistent and then deals with it, either forwarding it
+ * to the device or procesing it locally.
+ *
+ * In the i2400m, messages are basically commands that will carry an
+ * ack, so we use i2400m_msg_to_dev() and then deliver the ack back to
+ * user space. The rx.c code might intercept the response and use it
+ * to update the driver's state, but then it will pass it on so it can
+ * be relayed back to user space.
+ *
+ * Note that asynchronous events from the device are processed and
+ * sent to user space in rx.c.
+ */
+static
+int i2400m_op_msg_from_user(struct wimax_dev *wimax_dev,
+ const char *pipe_name,
+ const void *msg_buf, size_t msg_len,
+ const struct genl_info *genl_info)
+{
+ int result;
+ struct i2400m *i2400m = wimax_dev_to_i2400m(wimax_dev);
+ struct device *dev = i2400m_dev(i2400m);
+ struct sk_buff *ack_skb;
+
+ d_fnstart(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p "
+ "msg_len %zu genl_info %p)\n", wimax_dev, i2400m,
+ msg_buf, msg_len, genl_info);
+ ack_skb = i2400m_msg_to_dev(i2400m, msg_buf, msg_len);
+ result = PTR_ERR(ack_skb);
+ if (IS_ERR(ack_skb))
+ goto error_msg_to_dev;
+ if (unlikely(i2400m->trace_msg_from_user))
+ wimax_msg(&i2400m->wimax_dev, "trace",
+ msg_buf, msg_len, GFP_KERNEL);
+ result = wimax_msg_send(&i2400m->wimax_dev, ack_skb);
+error_msg_to_dev:
+ d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu "
+ "genl_info %p) = %d\n", wimax_dev, i2400m, msg_buf, msg_len,
+ genl_info, result);
+ return result;
+}
+
+
+/*
+ * Context to wait for a reset to finalize
+ */
+struct i2400m_reset_ctx {
+ struct completion completion;
+ int result;
+};
+
+
+/*
+ * WiMAX stack operation: reset a device
+ *
+ * @wimax_dev: device descriptor
+ *
+ * See the documentation for wimax_reset() and wimax_dev->op_reset for
+ * the requirements of this function. The WiMAX stack guarantees
+ * serialization on calls to this function.
+ *
+ * Do a warm reset on the device; if it fails, resort to a cold reset
+ * and return -ENODEV. On successful warm reset, we need to block
+ * until it is complete.
+ *
+ * The bus-driver implementation of reset takes care of falling back
+ * to cold reset if warm fails.
+ */
+static
+int i2400m_op_reset(struct wimax_dev *wimax_dev)
+{
+ int result;
+ struct i2400m *i2400m = wimax_dev_to_i2400m(wimax_dev);
+ struct device *dev = i2400m_dev(i2400m);
+ struct i2400m_reset_ctx ctx = {
+ .completion = COMPLETION_INITIALIZER_ONSTACK(ctx.completion),
+ .result = 0,
+ };
+
+ d_fnstart(4, dev, "(wimax_dev %p)\n", wimax_dev);
+ mutex_lock(&i2400m->init_mutex);
+ i2400m->reset_ctx = &ctx;
+ mutex_unlock(&i2400m->init_mutex);
+ result = i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+ if (result < 0)
+ goto out;
+ result = wait_for_completion_timeout(&ctx.completion, 4*HZ);
+ if (result == 0)
+ result = -ETIMEDOUT;
+ else if (result > 0)
+ result = ctx.result;
+ /* if result < 0, pass it on */
+ mutex_lock(&i2400m->init_mutex);
+ i2400m->reset_ctx = NULL;
+ mutex_unlock(&i2400m->init_mutex);
+out:
+ d_fnend(4, dev, "(wimax_dev %p) = %d\n", wimax_dev, result);
+ return result;
+}
+
+
+/*
+ * Check the MAC address we got from boot mode is ok
+ *
+ * @i2400m: device descriptor
+ *
+ * Returns: 0 if ok, < 0 errno code on error.
+ */
+static
+int i2400m_check_mac_addr(struct i2400m *i2400m)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct sk_buff *skb;
+ const struct i2400m_tlv_detailed_device_info *ddi;
+ struct net_device *net_dev = i2400m->wimax_dev.net_dev;
+ const unsigned char zeromac[ETH_ALEN] = { 0 };
+
+ d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+ skb = i2400m_get_device_info(i2400m);
+ if (IS_ERR(skb)) {
+ result = PTR_ERR(skb);
+ dev_err(dev, "Cannot verify MAC address, error reading: %d\n",
+ result);
+ goto error;
+ }
+ /* Extract MAC addresss */
+ ddi = (void *) skb->data;
+ BUILD_BUG_ON(ETH_ALEN != sizeof(ddi->mac_address));
+ d_printf(2, dev, "GET DEVICE INFO: mac addr "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ ddi->mac_address[0], ddi->mac_address[1],
+ ddi->mac_address[2], ddi->mac_address[3],
+ ddi->mac_address[4], ddi->mac_address[5]);
+ if (!memcmp(net_dev->perm_addr, ddi->mac_address,
+ sizeof(ddi->mac_address)))
+ goto ok;
+ dev_warn(dev, "warning: device reports a different MAC address "
+ "to that of boot mode's\n");
+ dev_warn(dev, "device reports %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ddi->mac_address[0], ddi->mac_address[1],
+ ddi->mac_address[2], ddi->mac_address[3],
+ ddi->mac_address[4], ddi->mac_address[5]);
+ dev_warn(dev, "boot mode reported %02x:%02x:%02x:%02x:%02x:%02x\n",
+ net_dev->perm_addr[0], net_dev->perm_addr[1],
+ net_dev->perm_addr[2], net_dev->perm_addr[3],
+ net_dev->perm_addr[4], net_dev->perm_addr[5]);
+ if (!memcmp(zeromac, ddi->mac_address, sizeof(zeromac)))
+ dev_err(dev, "device reports an invalid MAC address, "
+ "not updating\n");
+ else {
+ dev_warn(dev, "updating MAC address\n");
+ net_dev->addr_len = ETH_ALEN;
+ memcpy(net_dev->perm_addr, ddi->mac_address, ETH_ALEN);
+ memcpy(net_dev->dev_addr, ddi->mac_address, ETH_ALEN);
+ }
+ok:
+ result = 0;
+ kfree_skb(skb);
+error:
+ d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
+ return result;
+}
+
+
+/**
+ * __i2400m_dev_start - Bring up driver communication with the device
+ *
+ * @i2400m: device descriptor
+ * @flags: boot mode flags
+ *
+ * Returns: 0 if ok, < 0 errno code on error.
+ *
+ * Uploads firmware and brings up all the resources needed to be able
+ * to communicate with the device.
+ *
+ * TX needs to be setup before the bus-specific code (otherwise on
+ * shutdown, the bus-tx code could try to access it).
+ */
+static
+int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags)
+{
+ int result;
+ struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
+ struct net_device *net_dev = wimax_dev->net_dev;
+ struct device *dev = i2400m_dev(i2400m);
+ int times = 3;
+
+ d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+retry:
+ result = i2400m_dev_bootstrap(i2400m, flags);
+ if (result < 0) {
+ dev_err(dev, "cannot bootstrap device: %d\n", result);
+ goto error_bootstrap;
+ }
+ result = i2400m_tx_setup(i2400m);
+ if (result < 0)
+ goto error_tx_setup;
+ result = i2400m->bus_dev_start(i2400m);
+ if (result < 0)
+ goto error_bus_dev_start;
+ i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name);
+ if (i2400m->work_queue == NULL) {
+ result = -ENOMEM;
+ dev_err(dev, "cannot create workqueue\n");
+ goto error_create_workqueue;
+ }
+ /* At this point is ok to send commands to the device */
+ result = i2400m_check_mac_addr(i2400m);
+ if (result < 0)
+ goto error_check_mac_addr;
+ i2400m->ready = 1;
+ wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED);
+ result = i2400m_dev_initialize(i2400m);
+ if (result < 0)
+ goto error_dev_initialize;
+ /* At this point, reports will come for the device and set it
+ * to the right state if it is different than UNINITIALIZED */
+ d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n",
+ net_dev, i2400m, result);
+ return result;
+
+error_dev_initialize:
+error_check_mac_addr:
+ destroy_workqueue(i2400m->work_queue);
+error_create_workqueue:
+ i2400m->bus_dev_stop(i2400m);
+error_bus_dev_start:
+ i2400m_tx_release(i2400m);
+error_tx_setup:
+error_bootstrap:
+ if (result == -ERESTARTSYS && times-- > 0) {
+ flags = I2400M_BRI_SOFT;
+ goto retry;
+ }
+ d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n",
+ net_dev, i2400m, result);
+ return result;
+}
+
+
+static
+int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags)
+{
+ int result;
+ mutex_lock(&i2400m->init_mutex); /* Well, start the device */
+ result = __i2400m_dev_start(i2400m, bm_flags);
+ if (result >= 0)
+ i2400m->updown = 1;
+ mutex_unlock(&i2400m->init_mutex);
+ return result;
+}
+
+
+/**
+ * i2400m_dev_stop - Tear down driver communication with the device
+ *
+ * @i2400m: device descriptor
+ *
+ * Returns: 0 if ok, < 0 errno code on error.
+ *
+ * Releases all the resources allocated to communicate with the device.
+ */
+static
+void __i2400m_dev_stop(struct i2400m *i2400m)
+{
+ struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
+ struct device *dev = i2400m_dev(i2400m);
+
+ d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+ wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
+ i2400m_dev_shutdown(i2400m);
+ i2400m->ready = 0;
+ destroy_workqueue(i2400m->work_queue);
+ i2400m->bus_dev_stop(i2400m);
+ i2400m_tx_release(i2400m);
+ wimax_state_change(wimax_dev, WIMAX_ST_DOWN);
+ d_fnend(3, dev, "(i2400m %p) = 0\n", i2400m);
+}
+
+
+/*
+ * Watch out -- we only need to stop if there is a need for it. The
+ * device could have reset itself and failed to come up again (see
+ * _i2400m_dev_reset_handle()).
+ */
+static
+void i2400m_dev_stop(struct i2400m *i2400m)
+{
+ mutex_lock(&i2400m->init_mutex);
+ if (i2400m->updown) {
+ __i2400m_dev_stop(i2400m);
+ i2400m->updown = 0;
+ }
+ mutex_unlock(&i2400m->init_mutex);
+}
+
+
+/*
+ * The device has rebooted; fix up the device and the driver
+ *
+ * Tear down the driver communication with the device, reload the
+ * firmware and reinitialize the communication with the device.
+ *
+ * If someone calls a reset when the device's firmware is down, in
+ * theory we won't see it because we are not listening. However, just
+ * in case, leave the code to handle it.
+ *
+ * If there is a reset context, use it; this means someone is waiting
+ * for us to tell him when the reset operation is complete and the
+ * device is ready to rock again.
+ *
+ * NOTE: if we are in the process of bringing up or down the
+ * communication with the device [running i2400m_dev_start() or
+ * _stop()], don't do anything, let it fail and handle it.
+ *
+ * This function is ran always in a thread context
+ */
+static
+void __i2400m_dev_reset_handle(struct work_struct *ws)
+{
+ int result;
+ struct i2400m_work *iw = container_of(ws, struct i2400m_work, ws);
+ struct i2400m *i2400m = iw->i2400m;
+ struct device *dev = i2400m_dev(i2400m);
+ enum wimax_st wimax_state;
+ struct i2400m_reset_ctx *ctx = i2400m->reset_ctx;
+
+ d_fnstart(3, dev, "(ws %p i2400m %p)\n", ws, i2400m);
+ result = 0;
+ if (mutex_trylock(&i2400m->init_mutex) == 0) {
+ /* We are still in i2400m_dev_start() [let it fail] or
+ * i2400m_dev_stop() [we are shutting down anyway, so
+ * ignore it] or we are resetting somewhere else. */
+ dev_err(dev, "device rebooted\n");
+ i2400m_msg_to_dev_cancel_wait(i2400m, -ERESTARTSYS);
+ complete(&i2400m->msg_completion);
+ goto out;
+ }
+ wimax_state = wimax_state_get(&i2400m->wimax_dev);
+ if (wimax_state < WIMAX_ST_UNINITIALIZED) {
+ dev_info(dev, "device rebooted: it is down, ignoring\n");
+ goto out_unlock; /* ifconfig up/down wasn't called */
+ }
+ dev_err(dev, "device rebooted: reinitializing driver\n");
+ __i2400m_dev_stop(i2400m);
+ i2400m->updown = 0;
+ result = __i2400m_dev_start(i2400m,
+ I2400M_BRI_SOFT | I2400M_BRI_MAC_REINIT);
+ if (result < 0) {
+ dev_err(dev, "device reboot: cannot start the device: %d\n",
+ result);
+ result = i2400m->bus_reset(i2400m, I2400M_RT_BUS);
+ if (result >= 0)
+ result = -ENODEV;
+ } else
+ i2400m->updown = 1;
+out_unlock:
+ if (i2400m->reset_ctx) {
+ ctx->result = result;
+ complete(&ctx->completion);
+ }
+ mutex_unlock(&i2400m->init_mutex);
+out:
+ i2400m_put(i2400m);
+ kfree(iw);
+ d_fnend(3, dev, "(ws %p i2400m %p) = void\n", ws, i2400m);
+ return;
+}
+
+
+/**
+ * i2400m_dev_reset_handle - Handle a device's reset in a thread context
+ *
+ * Schedule a device reset handling out on a thread context, so it
+ * is safe to call from atomic context. We can't use the i2400m's
+ * queue as we are going to destroy it and reinitialize it as part of
+ * the driver bringup/bringup process.
+ *
+ * See __i2400m_dev_reset_handle() for details; that takes care of
+ * reinitializing the driver to handle the reset, calling into the
+ * bus-specific functions ops as needed.
+ */
+int i2400m_dev_reset_handle(struct i2400m *i2400m)
+{
+ return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle,
+ GFP_ATOMIC);
+}
+EXPORT_SYMBOL_GPL(i2400m_dev_reset_handle);
+
+
+/**
+ * i2400m_setup - bus-generic setup function for the i2400m device
+ *
+ * @i2400m: device descriptor (bus-specific parts have been initialized)
+ *
+ * Returns: 0 if ok, < 0 errno code on error.
+ *
+ * Initializes the bus-generic parts of the i2400m driver; the
+ * bus-specific parts have been initialized, function pointers filled
+ * out by the bus-specific probe function.
+ *
+ * As well, this registers the WiMAX and net device nodes. Once this
+ * function returns, the device is operative and has to be ready to
+ * receive and send network traffic and WiMAX control operations.
+ */
+int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
+{
+ int result = -ENODEV;
+ struct device *dev = i2400m_dev(i2400m);
+ struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
+ struct net_device *net_dev = i2400m->wimax_dev.net_dev;
+
+ d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+
+ snprintf(wimax_dev->name, sizeof(wimax_dev->name),
+ "i2400m-%s:%s", dev->bus->name, dev->bus_id);
+
+ i2400m->bm_cmd_buf = kzalloc(I2400M_BM_CMD_BUF_SIZE, GFP_KERNEL);
+ if (i2400m->bm_cmd_buf == NULL) {
+ dev_err(dev, "cannot allocate USB command buffer\n");
+ goto error_bm_cmd_kzalloc;
+ }
+ i2400m->bm_ack_buf = kzalloc(I2400M_BM_ACK_BUF_SIZE, GFP_KERNEL);
+ if (i2400m->bm_ack_buf == NULL) {
+ dev_err(dev, "cannot allocate USB ack buffer\n");
+ goto error_bm_ack_buf_kzalloc;
+ }
+ result = i2400m_bootrom_init(i2400m, bm_flags);
+ if (result < 0) {
+ dev_err(dev, "read mac addr: bootrom init "
+ "failed: %d\n", result);
+ goto error_bootrom_init;
+ }
+ result = i2400m_read_mac_addr(i2400m);
+ if (result < 0)
+ goto error_read_mac_addr;
+
+ result = register_netdev(net_dev); /* Okey dokey, bring it up */
+ if (result < 0) {
+ dev_err(dev, "cannot register i2400m network device: %d\n",
+ result);
+ goto error_register_netdev;
+ }
+ netif_carrier_off(net_dev);
+
+ result = i2400m_dev_start(i2400m, bm_flags);
+ if (result < 0)
+ goto error_dev_start;
+
+ i2400m->wimax_dev.op_msg_from_user = i2400m_op_msg_from_user;
+ i2400m->wimax_dev.op_rfkill_sw_toggle = i2400m_op_rfkill_sw_toggle;
+ i2400m->wimax_dev.op_reset = i2400m_op_reset;
+ result = wimax_dev_add(&i2400m->wimax_dev, net_dev);
+ if (result < 0)
+ goto error_wimax_dev_add;
+ /* User space needs to do some init stuff */
+ wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED);
+
+ /* Now setup all that requires a registered net and wimax device. */
+ result = i2400m_debugfs_add(i2400m);
+ if (result < 0) {
+ dev_err(dev, "cannot setup i2400m's debugfs: %d\n", result);
+ goto error_debugfs_setup;
+ }
+ d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
+ return result;
+
+error_debugfs_setup:
+ wimax_dev_rm(&i2400m->wimax_dev);
+error_wimax_dev_add:
+ i2400m_dev_stop(i2400m);
+error_dev_start:
+ unregister_netdev(net_dev);
+error_register_netdev:
+error_read_mac_addr:
+error_bootrom_init:
+ kfree(i2400m->bm_ack_buf);
+error_bm_ack_buf_kzalloc:
+ kfree(i2400m->bm_cmd_buf);
+error_bm_cmd_kzalloc:
+ d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
+ return result;
+}
+EXPORT_SYMBOL_GPL(i2400m_setup);
+
+
+/**
+ * i2400m_release - release the bus-generic driver resources
+ *
+ * Sends a disconnect message and undoes any setup done by i2400m_setup()
+ */
+void i2400m_release(struct i2400m *i2400m)
+{
+ struct device *dev = i2400m_dev(i2400m);
+
+ d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+ netif_stop_queue(i2400m->wimax_dev.net_dev);
+
+ i2400m_debugfs_rm(i2400m);
+ wimax_dev_rm(&i2400m->wimax_dev);
+ i2400m_dev_stop(i2400m);
+ unregister_netdev(i2400m->wimax_dev.net_dev);
+ kfree(i2400m->bm_ack_buf);
+ kfree(i2400m->bm_cmd_buf);
+ d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
+}
+EXPORT_SYMBOL_GPL(i2400m_release);
+
+
+static
+int __init i2400m_driver_init(void)
+{
+ return 0;
+}
+module_init(i2400m_driver_init);
+
+static
+void __exit i2400m_driver_exit(void)
+{
+ /* for scheds i2400m_dev_reset_handle() */
+ flush_scheduled_work();
+ return;
+}
+module_exit(i2400m_driver_exit);
+
+MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
+MODULE_DESCRIPTION("Intel 2400M WiMAX networking bus-generic driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
new file mode 100644
index 000000000000..1d8271f34c38
--- /dev/null
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -0,0 +1,1095 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Firmware uploader
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * - Initial implementation
+ *
+ *
+ * THE PROCEDURE
+ *
+ * (this is decribed for USB, but for SDIO is similar)
+ *
+ * The 2400m works in two modes: boot-mode or normal mode. In boot
+ * mode we can execute only a handful of commands targeted at
+ * uploading the firmware and launching it.
+ *
+ * The 2400m enters boot mode when it is first connected to the
+ * system, when it crashes and when you ask it to reboot. There are
+ * two submodes of the boot mode: signed and non-signed. Signed takes
+ * firmwares signed with a certain private key, non-signed takes any
+ * firmware. Normal hardware takes only signed firmware.
+ *
+ * Upon entrance to boot mode, the device sends a few zero length
+ * packets (ZLPs) on the notification endpoint, then a reboot barker
+ * (4 le32 words with value I2400M_{S,N}BOOT_BARKER). We ack it by
+ * sending the same barker on the bulk out endpoint. The device acks
+ * with a reboot ack barker (4 le32 words with value 0xfeedbabe) and
+ * then the device is fully rebooted. At this point we can upload the
+ * firmware.
+ *
+ * This process is accomplished by the i2400m_bootrom_init()
+ * function. All the device interaction happens through the
+ * i2400m_bm_cmd() [boot mode command]. Special return values will
+ * indicate if the device resets.
+ *
+ * After this, we read the MAC address and then (if needed)
+ * reinitialize the device. We need to read it ahead of time because
+ * in the future, we might not upload the firmware until userspace
+ * 'ifconfig up's the device.
+ *
+ * We can then upload the firmware file. The file is composed of a BCF
+ * header (basic data, keys and signatures) and a list of write
+ * commands and payloads. We first upload the header
+ * [i2400m_dnload_init()] and then pass the commands and payloads
+ * verbatim to the i2400m_bm_cmd() function
+ * [i2400m_dnload_bcf()]. Then we tell the device to jump to the new
+ * firmware [i2400m_dnload_finalize()].
+ *
+ * Once firmware is uploaded, we are good to go :)
+ *
+ * When we don't know in which mode we are, we first try by sending a
+ * warm reset request that will take us to boot-mode. If we time out
+ * waiting for a reboot barker, that means maybe we are already in
+ * boot mode, so we send a reboot barker.
+ *
+ * COMMAND EXECUTION
+ *
+ * This code (and process) is single threaded; for executing commands,
+ * we post a URB to the notification endpoint, post the command, wait
+ * for data on the notification buffer. We don't need to worry about
+ * others as we know we are the only ones in there.
+ *
+ * BACKEND IMPLEMENTATION
+ *
+ * This code is bus-generic; the bus-specific driver provides back end
+ * implementations to send a boot mode command to the device and to
+ * read an acknolwedgement from it (or an asynchronous notification)
+ * from it.
+ *
+ * ROADMAP
+ *
+ * i2400m_dev_bootstrap Called by __i2400m_dev_start()
+ * request_firmware
+ * i2400m_fw_check
+ * i2400m_fw_dnload
+ * release_firmware
+ *
+ * i2400m_fw_dnload
+ * i2400m_bootrom_init
+ * i2400m_bm_cmd
+ * i2400m->bus_reset
+ * i2400m_dnload_init
+ * i2400m_dnload_init_signed
+ * i2400m_dnload_init_nonsigned
+ * i2400m_download_chunk
+ * i2400m_bm_cmd
+ * i2400m_dnload_bcf
+ * i2400m_bm_cmd
+ * i2400m_dnload_finalize
+ * i2400m_bm_cmd
+ *
+ * i2400m_bm_cmd
+ * i2400m->bus_bm_cmd_send()
+ * i2400m->bus_bm_wait_for_ack
+ * __i2400m_bm_ack_verify
+ *
+ * i2400m_bm_cmd_prepare Used by bus-drivers to prep
+ * commands before sending
+ */
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include <linux/usb.h>
+#include "i2400m.h"
+
+
+#define D_SUBMODULE fw
+#include "debug-levels.h"
+
+
+static const __le32 i2400m_ACK_BARKER[4] = {
+ __constant_cpu_to_le32(I2400M_ACK_BARKER),
+ __constant_cpu_to_le32(I2400M_ACK_BARKER),
+ __constant_cpu_to_le32(I2400M_ACK_BARKER),
+ __constant_cpu_to_le32(I2400M_ACK_BARKER)
+};
+
+
+/**
+ * Prepare a boot-mode command for delivery
+ *
+ * @cmd: pointer to bootrom header to prepare
+ *
+ * Computes checksum if so needed. After calling this function, DO NOT
+ * modify the command or header as the checksum won't work anymore.
+ *
+ * We do it from here because some times we cannot do it in the
+ * original context the command was sent (it is a const), so when we
+ * copy it to our staging buffer, we add the checksum there.
+ */
+void i2400m_bm_cmd_prepare(struct i2400m_bootrom_header *cmd)
+{
+ if (i2400m_brh_get_use_checksum(cmd)) {
+ int i;
+ u32 checksum = 0;
+ const u32 *checksum_ptr = (void *) cmd->payload;
+ for (i = 0; i < cmd->data_size / 4; i++)
+ checksum += cpu_to_le32(*checksum_ptr++);
+ checksum += cmd->command + cmd->target_addr + cmd->data_size;
+ cmd->block_checksum = cpu_to_le32(checksum);
+ }
+}
+EXPORT_SYMBOL_GPL(i2400m_bm_cmd_prepare);
+
+
+/*
+ * Verify the ack data received
+ *
+ * Given a reply to a boot mode command, chew it and verify everything
+ * is ok.
+ *
+ * @opcode: opcode which generated this ack. For error messages.
+ * @ack: pointer to ack data we received
+ * @ack_size: size of that data buffer
+ * @flags: I2400M_BM_CMD_* flags we called the command with.
+ *
+ * Way too long function -- maybe it should be further split
+ */
+static
+ssize_t __i2400m_bm_ack_verify(struct i2400m *i2400m, int opcode,
+ struct i2400m_bootrom_header *ack,
+ size_t ack_size, int flags)
+{
+ ssize_t result = -ENOMEM;
+ struct device *dev = i2400m_dev(i2400m);
+
+ d_fnstart(8, dev, "(i2400m %p opcode %d ack %p size %zu)\n",
+ i2400m, opcode, ack, ack_size);
+ if (ack_size < sizeof(*ack)) {
+ result = -EIO;
+ dev_err(dev, "boot-mode cmd %d: HW BUG? notification didn't "
+ "return enough data (%zu bytes vs %zu expected)\n",
+ opcode, ack_size, sizeof(*ack));
+ goto error_ack_short;
+ }
+ if (ack_size == sizeof(i2400m_NBOOT_BARKER)
+ && memcmp(ack, i2400m_NBOOT_BARKER, sizeof(*ack)) == 0) {
+ result = -ERESTARTSYS;
+ i2400m->sboot = 0;
+ d_printf(6, dev, "boot-mode cmd %d: "
+ "HW non-signed boot barker\n", opcode);
+ goto error_reboot;
+ }
+ if (ack_size == sizeof(i2400m_SBOOT_BARKER)
+ && memcmp(ack, i2400m_SBOOT_BARKER, sizeof(*ack)) == 0) {
+ result = -ERESTARTSYS;
+ i2400m->sboot = 1;
+ d_printf(6, dev, "boot-mode cmd %d: HW signed reboot barker\n",
+ opcode);
+ goto error_reboot;
+ }
+ if (ack_size == sizeof(i2400m_ACK_BARKER)
+ && memcmp(ack, i2400m_ACK_BARKER, sizeof(*ack)) == 0) {
+ result = -EISCONN;
+ d_printf(3, dev, "boot-mode cmd %d: HW reboot ack barker\n",
+ opcode);
+ goto error_reboot_ack;
+ }
+ result = 0;
+ if (flags & I2400M_BM_CMD_RAW)
+ goto out_raw;
+ ack->data_size = le32_to_cpu(ack->data_size);
+ ack->target_addr = le32_to_cpu(ack->target_addr);
+ ack->block_checksum = le32_to_cpu(ack->block_checksum);
+ d_printf(5, dev, "boot-mode cmd %d: notification for opcode %u "
+ "response %u csum %u rr %u da %u\n",
+ opcode, i2400m_brh_get_opcode(ack),
+ i2400m_brh_get_response(ack),
+ i2400m_brh_get_use_checksum(ack),
+ i2400m_brh_get_response_required(ack),
+ i2400m_brh_get_direct_access(ack));
+ result = -EIO;
+ if (i2400m_brh_get_signature(ack) != 0xcbbc) {
+ dev_err(dev, "boot-mode cmd %d: HW BUG? wrong signature "
+ "0x%04x\n", opcode, i2400m_brh_get_signature(ack));
+ goto error_ack_signature;
+ }
+ if (opcode != -1 && opcode != i2400m_brh_get_opcode(ack)) {
+ dev_err(dev, "boot-mode cmd %d: HW BUG? "
+ "received response for opcode %u, expected %u\n",
+ opcode, i2400m_brh_get_opcode(ack), opcode);
+ goto error_ack_opcode;
+ }
+ if (i2400m_brh_get_response(ack) != 0) { /* failed? */
+ dev_err(dev, "boot-mode cmd %d: error; hw response %u\n",
+ opcode, i2400m_brh_get_response(ack));
+ goto error_ack_failed;
+ }
+ if (ack_size < ack->data_size + sizeof(*ack)) {
+ dev_err(dev, "boot-mode cmd %d: SW BUG "
+ "driver provided only %zu bytes for %zu bytes "
+ "of data\n", opcode, ack_size,
+ (size_t) le32_to_cpu(ack->data_size) + sizeof(*ack));
+ goto error_ack_short_buffer;
+ }
+ result = ack_size;
+ /* Don't you love this stack of empty targets? Well, I don't
+ * either, but it helps track exactly who comes in here and
+ * why :) */
+error_ack_short_buffer:
+error_ack_failed:
+error_ack_opcode:
+error_ack_signature:
+out_raw:
+error_reboot_ack:
+error_reboot:
+error_ack_short:
+ d_fnend(8, dev, "(i2400m %p opcode %d ack %p size %zu) = %d\n",
+ i2400m, opcode, ack, ack_size, (int) result);
+ return result;
+}
+
+
+/**
+ * i2400m_bm_cmd - Execute a boot mode command
+ *
+ * @cmd: buffer containing the command data (pointing at the header).
+ * This data can be ANYWHERE (for USB, we will copy it to an
+ * specific buffer). Make sure everything is in proper little
+ * endian.
+ *
+ * A raw buffer can be also sent, just cast it and set flags to
+ * I2400M_BM_CMD_RAW.
+ *
+ * This function will generate a checksum for you if the
+ * checksum bit in the command is set (unless I2400M_BM_CMD_RAW
+ * is set).
+ *
+ * You can use the i2400m->bm_cmd_buf to stage your commands and
+ * send them.
+ *
+ * If NULL, no command is sent (we just wait for an ack).
+ *
+ * @cmd_size: size of the command. Will be auto padded to the
+ * bus-specific drivers padding requirements.
+ *
+ * @ack: buffer where to place the acknowledgement. If it is a regular
+ * command response, all fields will be returned with the right,
+ * native endianess.
+ *
+ * You *cannot* use i2400m->bm_ack_buf for this buffer.
+ *
+ * @ack_size: size of @ack, 16 aligned; you need to provide at least
+ * sizeof(*ack) bytes and then enough to contain the return data
+ * from the command
+ *
+ * @flags: see I2400M_BM_CMD_* above.
+ *
+ * @returns: bytes received by the notification; if < 0, an errno code
+ * denoting an error or:
+ *
+ * -ERESTARTSYS The device has rebooted
+ *
+ * Executes a boot-mode command and waits for a response, doing basic
+ * validation on it; if a zero length response is received, it retries
+ * waiting for a response until a non-zero one is received (timing out
+ * after %I2400M_BOOT_RETRIES retries).
+ */
+static
+ssize_t i2400m_bm_cmd(struct i2400m *i2400m,
+ const struct i2400m_bootrom_header *cmd, size_t cmd_size,
+ struct i2400m_bootrom_header *ack, size_t ack_size,
+ int flags)
+{
+ ssize_t result = -ENOMEM, rx_bytes;
+ struct device *dev = i2400m_dev(i2400m);
+ int opcode = cmd == NULL ? -1 : i2400m_brh_get_opcode(cmd);
+
+ d_fnstart(6, dev, "(i2400m %p cmd %p size %zu ack %p size %zu)\n",
+ i2400m, cmd, cmd_size, ack, ack_size);
+ BUG_ON(ack_size < sizeof(*ack));
+ BUG_ON(i2400m->boot_mode == 0);
+
+ if (cmd != NULL) { /* send the command */
+ memcpy(i2400m->bm_cmd_buf, cmd, cmd_size);
+ result = i2400m->bus_bm_cmd_send(i2400m, cmd, cmd_size, flags);
+ if (result < 0)
+ goto error_cmd_send;
+ if ((flags & I2400M_BM_CMD_RAW) == 0)
+ d_printf(5, dev,
+ "boot-mode cmd %d csum %u rr %u da %u: "
+ "addr 0x%04x size %u block csum 0x%04x\n",
+ opcode, i2400m_brh_get_use_checksum(cmd),
+ i2400m_brh_get_response_required(cmd),
+ i2400m_brh_get_direct_access(cmd),
+ cmd->target_addr, cmd->data_size,
+ cmd->block_checksum);
+ }
+ result = i2400m->bus_bm_wait_for_ack(i2400m, ack, ack_size);
+ if (result < 0) {
+ dev_err(dev, "boot-mode cmd %d: error waiting for an ack: %d\n",
+ opcode, (int) result); /* bah, %zd doesn't work */
+ goto error_wait_for_ack;
+ }
+ rx_bytes = result;
+ /* verify the ack and read more if neccessary [result is the
+ * final amount of bytes we get in the ack] */
+ result = __i2400m_bm_ack_verify(i2400m, opcode, ack, ack_size, flags);
+ if (result < 0)
+ goto error_bad_ack;
+ /* Don't you love this stack of empty targets? Well, I don't
+ * either, but it helps track exactly who comes in here and
+ * why :) */
+ result = rx_bytes;
+error_bad_ack:
+error_wait_for_ack:
+error_cmd_send:
+ d_fnend(6, dev, "(i2400m %p cmd %p size %zu ack %p size %zu) = %d\n",
+ i2400m, cmd, cmd_size, ack, ack_size, (int) result);
+ return result;
+}
+
+
+/**
+ * i2400m_download_chunk - write a single chunk of data to the device's memory
+ *
+ * @i2400m: device descriptor
+ * @buf: the buffer to write
+ * @buf_len: length of the buffer to write
+ * @addr: address in the device memory space
+ * @direct: bootrom write mode
+ * @do_csum: should a checksum validation be performed
+ */
+static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk,
+ size_t __chunk_len, unsigned long addr,
+ unsigned int direct, unsigned int do_csum)
+{
+ int ret;
+ size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_PAD);
+ struct device *dev = i2400m_dev(i2400m);
+ struct {
+ struct i2400m_bootrom_header cmd;
+ u8 cmd_payload[chunk_len];
+ } __attribute__((packed)) *buf;
+ struct i2400m_bootrom_header ack;
+
+ d_fnstart(5, dev, "(i2400m %p chunk %p __chunk_len %zu addr 0x%08lx "
+ "direct %u do_csum %u)\n", i2400m, chunk, __chunk_len,
+ addr, direct, do_csum);
+ buf = i2400m->bm_cmd_buf;
+ memcpy(buf->cmd_payload, chunk, __chunk_len);
+ memset(buf->cmd_payload + __chunk_len, 0xad, chunk_len - __chunk_len);
+
+ buf->cmd.command = i2400m_brh_command(I2400M_BRH_WRITE,
+ __chunk_len & 0x3 ? 0 : do_csum,
+ __chunk_len & 0xf ? 0 : direct);
+ buf->cmd.target_addr = cpu_to_le32(addr);
+ buf->cmd.data_size = cpu_to_le32(__chunk_len);
+ ret = i2400m_bm_cmd(i2400m, &buf->cmd, sizeof(buf->cmd) + chunk_len,
+ &ack, sizeof(ack), 0);
+ if (ret >= 0)
+ ret = 0;
+ d_fnend(5, dev, "(i2400m %p chunk %p __chunk_len %zu addr 0x%08lx "
+ "direct %u do_csum %u) = %d\n", i2400m, chunk, __chunk_len,
+ addr, direct, do_csum, ret);
+ return ret;
+}
+
+
+/*
+ * Download a BCF file's sections to the device
+ *
+ * @i2400m: device descriptor
+ * @bcf: pointer to firmware data (followed by the payloads). Assumed
+ * verified and consistent.
+ * @bcf_len: length (in bytes) of the @bcf buffer.
+ *
+ * Returns: < 0 errno code on error or the offset to the jump instruction.
+ *
+ * Given a BCF file, downloads each section (a command and a payload)
+ * to the device's address space. Actually, it just executes each
+ * command i the BCF file.
+ *
+ * The section size has to be aligned to 4 bytes AND the padding has
+ * to be taken from the firmware file, as the signature takes it into
+ * account.
+ */
+static
+ssize_t i2400m_dnload_bcf(struct i2400m *i2400m,
+ const struct i2400m_bcf_hdr *bcf, size_t bcf_len)
+{
+ ssize_t ret;
+ struct device *dev = i2400m_dev(i2400m);
+ size_t offset, /* iterator offset */
+ data_size, /* Size of the data payload */
+ section_size, /* Size of the whole section (cmd + payload) */
+ section = 1;
+ const struct i2400m_bootrom_header *bh;
+ struct i2400m_bootrom_header ack;
+
+ d_fnstart(3, dev, "(i2400m %p bcf %p bcf_len %zu)\n",
+ i2400m, bcf, bcf_len);
+ /* Iterate over the command blocks in the BCF file that start
+ * after the header */
+ offset = le32_to_cpu(bcf->header_len) * sizeof(u32);
+ while (1) { /* start sending the file */
+ bh = (void *) bcf + offset;
+ data_size = le32_to_cpu(bh->data_size);
+ section_size = ALIGN(sizeof(*bh) + data_size, 4);
+ d_printf(7, dev,
+ "downloading section #%zu (@%zu %zu B) to 0x%08x\n",
+ section, offset, sizeof(*bh) + data_size,
+ le32_to_cpu(bh->target_addr));
+ if (i2400m_brh_get_opcode(bh) == I2400M_BRH_SIGNED_JUMP) {
+ /* Secure boot needs to stop here */
+ d_printf(5, dev, "signed jump found @%zu\n", offset);
+ break;
+ }
+ if (offset + section_size == bcf_len)
+ /* Non-secure boot stops here */
+ break;
+ if (offset + section_size > bcf_len) {
+ dev_err(dev, "fw %s: bad section #%zu, "
+ "end (@%zu) beyond EOF (@%zu)\n",
+ i2400m->bus_fw_name, section,
+ offset + section_size, bcf_len);
+ ret = -EINVAL;
+ goto error_section_beyond_eof;
+ }
+ __i2400m_msleep(20);
+ ret = i2400m_bm_cmd(i2400m, bh, section_size,
+ &ack, sizeof(ack), I2400M_BM_CMD_RAW);
+ if (ret < 0) {
+ dev_err(dev, "fw %s: section #%zu (@%zu %zu B) "
+ "failed %d\n", i2400m->bus_fw_name, section,
+ offset, sizeof(*bh) + data_size, (int) ret);
+ goto error_send;
+ }
+ offset += section_size;
+ section++;
+ }
+ ret = offset;
+error_section_beyond_eof:
+error_send:
+ d_fnend(3, dev, "(i2400m %p bcf %p bcf_len %zu) = %d\n",
+ i2400m, bcf, bcf_len, (int) ret);
+ return ret;
+}
+
+
+/*
+ * Do the final steps of uploading firmware
+ *
+ * Depending on the boot mode (signed vs non-signed), different
+ * actions need to be taken.
+ */
+static
+int i2400m_dnload_finalize(struct i2400m *i2400m,
+ const struct i2400m_bcf_hdr *bcf, size_t offset)
+{
+ int ret = 0;
+ struct device *dev = i2400m_dev(i2400m);
+ struct i2400m_bootrom_header *cmd, ack;
+ struct {
+ struct i2400m_bootrom_header cmd;
+ u8 cmd_pl[0];
+ } __attribute__((packed)) *cmd_buf;
+ size_t signature_block_offset, signature_block_size;
+
+ d_fnstart(3, dev, "offset %zu\n", offset);
+ cmd = (void *) bcf + offset;
+ if (i2400m->sboot == 0) {
+ struct i2400m_bootrom_header jump_ack;
+ d_printf(3, dev, "unsecure boot, jumping to 0x%08x\n",
+ le32_to_cpu(cmd->target_addr));
+ i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP);
+ cmd->data_size = 0;
+ ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
+ &jump_ack, sizeof(jump_ack), 0);
+ } else {
+ d_printf(3, dev, "secure boot, jumping to 0x%08x\n",
+ le32_to_cpu(cmd->target_addr));
+ cmd_buf = i2400m->bm_cmd_buf;
+ memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd));
+ signature_block_offset =
+ sizeof(*bcf)
+ + le32_to_cpu(bcf->key_size) * sizeof(u32)
+ + le32_to_cpu(bcf->exponent_size) * sizeof(u32);
+ signature_block_size =
+ le32_to_cpu(bcf->modulus_size) * sizeof(u32);
+ memcpy(cmd_buf->cmd_pl, (void *) bcf + signature_block_offset,
+ signature_block_size);
+ ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd,
+ sizeof(cmd_buf->cmd) + signature_block_size,
+ &ack, sizeof(ack), I2400M_BM_CMD_RAW);
+ }
+ d_fnend(3, dev, "returning %d\n", ret);
+ return ret;
+}
+
+
+/**
+ * i2400m_bootrom_init - Reboots a powered device into boot mode
+ *
+ * @i2400m: device descriptor
+ * @flags:
+ * I2400M_BRI_SOFT: a reboot notification has been seen
+ * already, so don't wait for it.
+ *
+ * I2400M_BRI_NO_REBOOT: Don't send a reboot command, but wait
+ * for a reboot barker notification. This is a one shot; if
+ * the state machine needs to send a reboot command it will.
+ *
+ * Returns:
+ *
+ * < 0 errno code on error, 0 if ok.
+ *
+ * i2400m->sboot set to 0 for unsecure boot process, 1 for secure
+ * boot process.
+ *
+ * Description:
+ *
+ * Tries hard enough to put the device in boot-mode. There are two
+ * main phases to this:
+ *
+ * a. (1) send a reboot command and (2) get a reboot barker
+ * b. (1) ack the reboot sending a reboot barker and (2) getting an
+ * ack barker in return
+ *
+ * We want to skip (a) in some cases [soft]. The state machine is
+ * horrible, but it is basically: on each phase, send what has to be
+ * sent (if any), wait for the answer and act on the answer. We might
+ * have to backtrack and retry, so we keep a max tries counter for
+ * that.
+ *
+ * If we get a timeout after sending a warm reset, we do it again.
+ */
+int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct i2400m_bootrom_header *cmd;
+ struct i2400m_bootrom_header ack;
+ int count = I2400M_BOOT_RETRIES;
+ int ack_timeout_cnt = 1;
+
+ BUILD_BUG_ON(sizeof(*cmd) != sizeof(i2400m_NBOOT_BARKER));
+ BUILD_BUG_ON(sizeof(ack) != sizeof(i2400m_ACK_BARKER));
+
+ d_fnstart(4, dev, "(i2400m %p flags 0x%08x)\n", i2400m, flags);
+ result = -ENOMEM;
+ cmd = i2400m->bm_cmd_buf;
+ if (flags & I2400M_BRI_SOFT)
+ goto do_reboot_ack;
+do_reboot:
+ if (--count < 0)
+ goto error_timeout;
+ d_printf(4, dev, "device reboot: reboot command [%d # left]\n",
+ count);
+ if ((flags & I2400M_BRI_NO_REBOOT) == 0)
+ i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+ result = i2400m_bm_cmd(i2400m, NULL, 0, &ack, sizeof(ack),
+ I2400M_BM_CMD_RAW);
+ flags &= ~I2400M_BRI_NO_REBOOT;
+ switch (result) {
+ case -ERESTARTSYS:
+ d_printf(4, dev, "device reboot: got reboot barker\n");
+ break;
+ case -EISCONN: /* we don't know how it got here...but we follow it */
+ d_printf(4, dev, "device reboot: got ack barker - whatever\n");
+ goto do_reboot;
+ case -ETIMEDOUT: /* device has timed out, we might be in boot
+ * mode already and expecting an ack, let's try
+ * that */
+ dev_info(dev, "warm reset timed out, trying an ack\n");
+ goto do_reboot_ack;
+ case -EPROTO:
+ case -ESHUTDOWN: /* dev is gone */
+ case -EINTR: /* user cancelled */
+ goto error_dev_gone;
+ default:
+ dev_err(dev, "device reboot: error %d while waiting "
+ "for reboot barker - rebooting\n", result);
+ goto do_reboot;
+ }
+ /* At this point we ack back with 4 REBOOT barkers and expect
+ * 4 ACK barkers. This is ugly, as we send a raw command --
+ * hence the cast. _bm_cmd() will catch the reboot ack
+ * notification and report it as -EISCONN. */
+do_reboot_ack:
+ d_printf(4, dev, "device reboot ack: sending ack [%d # left]\n", count);
+ if (i2400m->sboot == 0)
+ memcpy(cmd, i2400m_NBOOT_BARKER,
+ sizeof(i2400m_NBOOT_BARKER));
+ else
+ memcpy(cmd, i2400m_SBOOT_BARKER,
+ sizeof(i2400m_SBOOT_BARKER));
+ result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
+ &ack, sizeof(ack), I2400M_BM_CMD_RAW);
+ switch (result) {
+ case -ERESTARTSYS:
+ d_printf(4, dev, "reboot ack: got reboot barker - retrying\n");
+ if (--count < 0)
+ goto error_timeout;
+ goto do_reboot_ack;
+ case -EISCONN:
+ d_printf(4, dev, "reboot ack: got ack barker - good\n");
+ break;
+ case -ETIMEDOUT: /* no response, maybe it is the other type? */
+ if (ack_timeout_cnt-- >= 0) {
+ d_printf(4, dev, "reboot ack timedout: "
+ "trying the other type?\n");
+ i2400m->sboot = !i2400m->sboot;
+ goto do_reboot_ack;
+ } else {
+ dev_err(dev, "reboot ack timedout too long: "
+ "trying reboot\n");
+ goto do_reboot;
+ }
+ break;
+ case -EPROTO:
+ case -ESHUTDOWN: /* dev is gone */
+ goto error_dev_gone;
+ default:
+ dev_err(dev, "device reboot ack: error %d while waiting for "
+ "reboot ack barker - rebooting\n", result);
+ goto do_reboot;
+ }
+ d_printf(2, dev, "device reboot ack: got ack barker - boot done\n");
+ result = 0;
+exit_timeout:
+error_dev_gone:
+ d_fnend(4, dev, "(i2400m %p flags 0x%08x) = %d\n",
+ i2400m, flags, result);
+ return result;
+
+error_timeout:
+ dev_err(dev, "Timed out waiting for reboot ack, resetting\n");
+ i2400m->bus_reset(i2400m, I2400M_RT_BUS);
+ result = -ETIMEDOUT;
+ goto exit_timeout;
+}
+
+
+/*
+ * Read the MAC addr
+ *
+ * The position this function reads is fixed in device memory and
+ * always available, even without firmware.
+ *
+ * Note we specify we want to read only six bytes, but provide space
+ * for 16, as we always get it rounded up.
+ */
+int i2400m_read_mac_addr(struct i2400m *i2400m)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct net_device *net_dev = i2400m->wimax_dev.net_dev;
+ struct i2400m_bootrom_header *cmd;
+ struct {
+ struct i2400m_bootrom_header ack;
+ u8 ack_pl[16];
+ } __attribute__((packed)) ack_buf;
+
+ d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
+ cmd = i2400m->bm_cmd_buf;
+ cmd->command = i2400m_brh_command(I2400M_BRH_READ, 0, 1);
+ cmd->target_addr = cpu_to_le32(0x00203fe8);
+ cmd->data_size = cpu_to_le32(6);
+ result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
+ &ack_buf.ack, sizeof(ack_buf), 0);
+ if (result < 0) {
+ dev_err(dev, "BM: read mac addr failed: %d\n", result);
+ goto error_read_mac;
+ }
+ d_printf(2, dev,
+ "mac addr is %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ack_buf.ack_pl[0], ack_buf.ack_pl[1],
+ ack_buf.ack_pl[2], ack_buf.ack_pl[3],
+ ack_buf.ack_pl[4], ack_buf.ack_pl[5]);
+ if (i2400m->bus_bm_mac_addr_impaired == 1) {
+ ack_buf.ack_pl[0] = 0x00;
+ ack_buf.ack_pl[1] = 0x16;
+ ack_buf.ack_pl[2] = 0xd3;
+ get_random_bytes(&ack_buf.ack_pl[3], 3);
+ dev_err(dev, "BM is MAC addr impaired, faking MAC addr to "
+ "mac addr is %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ack_buf.ack_pl[0], ack_buf.ack_pl[1],
+ ack_buf.ack_pl[2], ack_buf.ack_pl[3],
+ ack_buf.ack_pl[4], ack_buf.ack_pl[5]);
+ result = 0;
+ }
+ net_dev->addr_len = ETH_ALEN;
+ memcpy(net_dev->perm_addr, ack_buf.ack_pl, ETH_ALEN);
+ memcpy(net_dev->dev_addr, ack_buf.ack_pl, ETH_ALEN);
+error_read_mac:
+ d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, result);
+ return result;
+}
+
+
+/*
+ * Initialize a non signed boot
+ *
+ * This implies sending some magic values to the device's memory. Note
+ * we convert the values to little endian in the same array
+ * declaration.
+ */
+static
+int i2400m_dnload_init_nonsigned(struct i2400m *i2400m)
+{
+#define POKE(a, d) { \
+ .address = __constant_cpu_to_le32(a), \
+ .data = __constant_cpu_to_le32(d) \
+}
+ static const struct {
+ __le32 address;
+ __le32 data;
+ } i2400m_pokes[] = {
+ POKE(0x081A58, 0xA7810230),
+ POKE(0x080040, 0x00000000),
+ POKE(0x080048, 0x00000082),
+ POKE(0x08004C, 0x0000081F),
+ POKE(0x080054, 0x00000085),
+ POKE(0x080058, 0x00000180),
+ POKE(0x08005C, 0x00000018),
+ POKE(0x080060, 0x00000010),
+ POKE(0x080574, 0x00000001),
+ POKE(0x080550, 0x00000005),
+ POKE(0xAE0000, 0x00000000),
+ };
+#undef POKE
+ unsigned i;
+ int ret;
+ struct device *dev = i2400m_dev(i2400m);
+
+ dev_warn(dev, "WARNING!!! non-signed boot UNTESTED PATH!\n");
+
+ d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
+ for (i = 0; i < ARRAY_SIZE(i2400m_pokes); i++) {
+ ret = i2400m_download_chunk(i2400m, &i2400m_pokes[i].data,
+ sizeof(i2400m_pokes[i].data),
+ i2400m_pokes[i].address, 1, 1);
+ if (ret < 0)
+ break;
+ }
+ d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret);
+ return ret;
+}
+
+
+/*
+ * Initialize the signed boot process
+ *
+ * @i2400m: device descriptor
+ *
+ * @bcf_hdr: pointer to the firmware header; assumes it is fully in
+ * memory (it has gone through basic validation).
+ *
+ * Returns: 0 if ok, < 0 errno code on error, -ERESTARTSYS if the hw
+ * rebooted.
+ *
+ * This writes the firmware BCF header to the device using the
+ * HASH_PAYLOAD_ONLY command.
+ */
+static
+int i2400m_dnload_init_signed(struct i2400m *i2400m,
+ const struct i2400m_bcf_hdr *bcf_hdr)
+{
+ int ret;
+ struct device *dev = i2400m_dev(i2400m);
+ struct {
+ struct i2400m_bootrom_header cmd;
+ struct i2400m_bcf_hdr cmd_pl;
+ } __attribute__((packed)) *cmd_buf;
+ struct i2400m_bootrom_header ack;
+
+ d_fnstart(5, dev, "(i2400m %p bcf_hdr %p)\n", i2400m, bcf_hdr);
+ cmd_buf = i2400m->bm_cmd_buf;
+ cmd_buf->cmd.command =
+ i2400m_brh_command(I2400M_BRH_HASH_PAYLOAD_ONLY, 0, 0);
+ cmd_buf->cmd.target_addr = 0;
+ cmd_buf->cmd.data_size = cpu_to_le32(sizeof(cmd_buf->cmd_pl));
+ memcpy(&cmd_buf->cmd_pl, bcf_hdr, sizeof(*bcf_hdr));
+ ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd, sizeof(*cmd_buf),
+ &ack, sizeof(ack), 0);
+ if (ret >= 0)
+ ret = 0;
+ d_fnend(5, dev, "(i2400m %p bcf_hdr %p) = %d\n", i2400m, bcf_hdr, ret);
+ return ret;
+}
+
+
+/*
+ * Initialize the firmware download at the device size
+ *
+ * Multiplex to the one that matters based on the device's mode
+ * (signed or non-signed).
+ */
+static
+int i2400m_dnload_init(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ u32 module_id = le32_to_cpu(bcf->module_id);
+
+ if (i2400m->sboot == 0
+ && (module_id & I2400M_BCF_MOD_ID_POKES) == 0) {
+ /* non-signed boot process without pokes */
+ result = i2400m_dnload_init_nonsigned(i2400m);
+ if (result == -ERESTARTSYS)
+ return result;
+ if (result < 0)
+ dev_err(dev, "fw %s: non-signed download "
+ "initialization failed: %d\n",
+ i2400m->bus_fw_name, result);
+ } else if (i2400m->sboot == 0
+ && (module_id & I2400M_BCF_MOD_ID_POKES)) {
+ /* non-signed boot process with pokes, nothing to do */
+ result = 0;
+ } else { /* signed boot process */
+ result = i2400m_dnload_init_signed(i2400m, bcf);
+ if (result == -ERESTARTSYS)
+ return result;
+ if (result < 0)
+ dev_err(dev, "fw %s: signed boot download "
+ "initialization failed: %d\n",
+ i2400m->bus_fw_name, result);
+ }
+ return result;
+}
+
+
+/*
+ * Run quick consistency tests on the firmware file
+ *
+ * Check for the firmware being made for the i2400m device,
+ * etc...These checks are mostly informative, as the device will make
+ * them too; but the driver's response is more informative on what
+ * went wrong.
+ */
+static
+int i2400m_fw_check(struct i2400m *i2400m,
+ const struct i2400m_bcf_hdr *bcf,
+ size_t bcf_size)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ unsigned module_type, header_len, major_version, minor_version,
+ module_id, module_vendor, date, size;
+
+ /* Check hard errors */
+ result = -EINVAL;
+ if (bcf_size < sizeof(*bcf)) { /* big enough header? */
+ dev_err(dev, "firmware %s too short: "
+ "%zu B vs %zu (at least) expected\n",
+ i2400m->bus_fw_name, bcf_size, sizeof(*bcf));
+ goto error;
+ }
+
+ module_type = bcf->module_type;
+ header_len = sizeof(u32) * le32_to_cpu(bcf->header_len);
+ major_version = le32_to_cpu(bcf->header_version) & 0xffff0000 >> 16;
+ minor_version = le32_to_cpu(bcf->header_version) & 0x0000ffff;
+ module_id = le32_to_cpu(bcf->module_id);
+ module_vendor = le32_to_cpu(bcf->module_vendor);
+ date = le32_to_cpu(bcf->date);
+ size = sizeof(u32) * le32_to_cpu(bcf->size);
+
+ if (bcf_size != size) { /* annoyingly paranoid */
+ dev_err(dev, "firmware %s: bad size, got "
+ "%zu B vs %u expected\n",
+ i2400m->bus_fw_name, bcf_size, size);
+ goto error;
+ }
+
+ d_printf(2, dev, "type 0x%x id 0x%x vendor 0x%x; header v%u.%u (%zu B) "
+ "date %08x (%zu B)\n",
+ module_type, module_id, module_vendor,
+ major_version, minor_version, (size_t) header_len,
+ date, (size_t) size);
+
+ if (module_type != 6) { /* built for the right hardware? */
+ dev_err(dev, "bad fw %s: unexpected module type 0x%x; "
+ "aborting\n", i2400m->bus_fw_name, module_type);
+ goto error;
+ }
+
+ /* Check soft-er errors */
+ result = 0;
+ if (module_vendor != 0x8086)
+ dev_err(dev, "bad fw %s? unexpected vendor 0x%04x\n",
+ i2400m->bus_fw_name, module_vendor);
+ if (date < 0x20080300)
+ dev_err(dev, "bad fw %s? build date too old %08x\n",
+ i2400m->bus_fw_name, date);
+error:
+ return result;
+}
+
+
+/*
+ * Download the firmware to the device
+ *
+ * @i2400m: device descriptor
+ * @bcf: pointer to loaded (and minimally verified for consistency)
+ * firmware
+ * @bcf_size: size of the @bcf buffer (header plus payloads)
+ *
+ * The process for doing this is described in this file's header.
+ *
+ * Note we only reinitialize boot-mode if the flags say so. Some hw
+ * iterations need it, some don't. In any case, if we loop, we always
+ * need to reinitialize the boot room, hence the flags modification.
+ */
+static
+int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf,
+ size_t bcf_size, enum i2400m_bri flags)
+{
+ int ret = 0;
+ struct device *dev = i2400m_dev(i2400m);
+ int count = I2400M_BOOT_RETRIES;
+
+ d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n",
+ i2400m, bcf, bcf_size);
+ i2400m->boot_mode = 1;
+hw_reboot:
+ if (count-- == 0) {
+ ret = -ERESTARTSYS;
+ dev_err(dev, "device rebooted too many times, aborting\n");
+ goto error_too_many_reboots;
+ }
+ if (flags & I2400M_BRI_MAC_REINIT) {
+ ret = i2400m_bootrom_init(i2400m, flags);
+ if (ret < 0) {
+ dev_err(dev, "bootrom init failed: %d\n", ret);
+ goto error_bootrom_init;
+ }
+ }
+ flags |= I2400M_BRI_MAC_REINIT;
+
+ /*
+ * Initialize the download, push the bytes to the device and
+ * then jump to the new firmware. Note @ret is passed with the
+ * offset of the jump instruction to _dnload_finalize()
+ */
+ ret = i2400m_dnload_init(i2400m, bcf); /* Init device's dnload */
+ if (ret == -ERESTARTSYS)
+ goto error_dev_rebooted;
+ if (ret < 0)
+ goto error_dnload_init;
+
+ ret = i2400m_dnload_bcf(i2400m, bcf, bcf_size);
+ if (ret == -ERESTARTSYS)
+ goto error_dev_rebooted;
+ if (ret < 0) {
+ dev_err(dev, "fw %s: download failed: %d\n",
+ i2400m->bus_fw_name, ret);
+ goto error_dnload_bcf;
+ }
+
+ ret = i2400m_dnload_finalize(i2400m, bcf, ret);
+ if (ret == -ERESTARTSYS)
+ goto error_dev_rebooted;
+ if (ret < 0) {
+ dev_err(dev, "fw %s: "
+ "download finalization failed: %d\n",
+ i2400m->bus_fw_name, ret);
+ goto error_dnload_finalize;
+ }
+
+ d_printf(2, dev, "fw %s successfully uploaded\n",
+ i2400m->bus_fw_name);
+ i2400m->boot_mode = 0;
+error_dnload_finalize:
+error_dnload_bcf:
+error_dnload_init:
+error_bootrom_init:
+error_too_many_reboots:
+ d_fnend(5, dev, "(i2400m %p bcf %p size %zu) = %d\n",
+ i2400m, bcf, bcf_size, ret);
+ return ret;
+
+error_dev_rebooted:
+ dev_err(dev, "device rebooted, %d tries left\n", count);
+ /* we got the notification already, no need to wait for it again */
+ flags |= I2400M_BRI_SOFT;
+ goto hw_reboot;
+}
+
+
+/**
+ * i2400m_dev_bootstrap - Bring the device to a known state and upload firmware
+ *
+ * @i2400m: device descriptor
+ *
+ * Returns: >= 0 if ok, < 0 errno code on error.
+ *
+ * This sets up the firmware upload environment, loads the firmware
+ * file from disk, verifies and then calls the firmware upload process
+ * per se.
+ *
+ * Can be called either from probe, or after a warm reset. Can not be
+ * called from within an interrupt. All the flow in this code is
+ * single-threade; all I/Os are synchronous.
+ */
+int i2400m_dev_bootstrap(struct i2400m *i2400m, enum i2400m_bri flags)
+{
+ int ret = 0;
+ struct device *dev = i2400m_dev(i2400m);
+ const struct firmware *fw;
+ const struct i2400m_bcf_hdr *bcf; /* Firmware data */
+
+ d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
+ /* Load firmware files to memory. */
+ ret = request_firmware(&fw, i2400m->bus_fw_name, dev);
+ if (ret) {
+ dev_err(dev, "fw %s: request failed: %d\n",
+ i2400m->bus_fw_name, ret);
+ goto error_fw_req;
+ }
+ bcf = (void *) fw->data;
+
+ ret = i2400m_fw_check(i2400m, bcf, fw->size);
+ if (ret < 0)
+ goto error_fw_bad;
+ ret = i2400m_fw_dnload(i2400m, bcf, fw->size, flags);
+error_fw_bad:
+ release_firmware(fw);
+error_fw_req:
+ d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i2400m_dev_bootstrap);
diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h
new file mode 100644
index 000000000000..08c2fb739234
--- /dev/null
+++ b/drivers/net/wimax/i2400m/i2400m-sdio.h
@@ -0,0 +1,132 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * SDIO-specific i2400m driver definitions
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Brian Bian <brian.bian@intel.com>
+ * Dirk Brandewie <dirk.j.brandewie@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ * - Initial implementation
+ *
+ *
+ * This driver implements the bus-specific part of the i2400m for
+ * SDIO. Check i2400m.h for a generic driver description.
+ *
+ * ARCHITECTURE
+ *
+ * This driver sits under the bus-generic i2400m driver, providing the
+ * connection to the device.
+ *
+ * When probed, all the function pointers are setup and then the
+ * bus-generic code called. The generic driver will then use the
+ * provided pointers for uploading firmware (i2400ms_bus_bm*() in
+ * sdio-fw.c) and then setting up the device (i2400ms_dev_*() in
+ * sdio.c).
+ *
+ * Once firmware is uploaded, TX functions (sdio-tx.c) are called when
+ * data is ready for transmission in the TX fifo; then the SDIO IRQ is
+ * fired and data is available (sdio-rx.c), it is sent to the generic
+ * driver for processing with i2400m_rx.
+ */
+
+#ifndef __I2400M_SDIO_H__
+#define __I2400M_SDIO_H__
+
+#include "i2400m.h"
+
+/* Host-Device interface for SDIO */
+enum {
+ I2400MS_BLK_SIZE = 256,
+ I2400MS_PL_SIZE_MAX = 0x3E00,
+
+ I2400MS_DATA_ADDR = 0x0,
+ I2400MS_INTR_STATUS_ADDR = 0x13,
+ I2400MS_INTR_CLEAR_ADDR = 0x13,
+ I2400MS_INTR_ENABLE_ADDR = 0x14,
+ I2400MS_INTR_GET_SIZE_ADDR = 0x2C,
+ /* The number of ticks to wait for the device to signal that
+ * it is ready */
+ I2400MS_INIT_SLEEP_INTERVAL = 10,
+};
+
+
+/**
+ * struct i2400ms - descriptor for a SDIO connected i2400m
+ *
+ * @i2400m: bus-generic i2400m implementation; has to be first (see
+ * it's documentation in i2400m.h).
+ *
+ * @func: pointer to our SDIO function
+ *
+ * @tx_worker: workqueue struct used to TX data when the bus-generic
+ * code signals packets are pending for transmission to the device.
+ *
+ * @tx_workqueue: workqeueue used for data TX; we don't use the
+ * system's workqueue as that might cause deadlocks with code in
+ * the bus-generic driver.
+ */
+struct i2400ms {
+ struct i2400m i2400m; /* FIRST! See doc */
+ struct sdio_func *func;
+
+ struct work_struct tx_worker;
+ struct workqueue_struct *tx_workqueue;
+ char tx_wq_name[32];
+
+ struct dentry *debugfs_dentry;
+};
+
+
+static inline
+void i2400ms_init(struct i2400ms *i2400ms)
+{
+ i2400m_init(&i2400ms->i2400m);
+}
+
+
+extern int i2400ms_rx_setup(struct i2400ms *);
+extern void i2400ms_rx_release(struct i2400ms *);
+extern ssize_t __i2400ms_rx_get_size(struct i2400ms *);
+
+extern int i2400ms_tx_setup(struct i2400ms *);
+extern void i2400ms_tx_release(struct i2400ms *);
+extern void i2400ms_bus_tx_kick(struct i2400m *);
+
+extern ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *,
+ const struct i2400m_bootrom_header *,
+ size_t, int);
+extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *,
+ struct i2400m_bootrom_header *,
+ size_t);
+#endif /* #ifndef __I2400M_SDIO_H__ */
diff --git a/drivers/net/wimax/i2400m/i2400m-usb.h b/drivers/net/wimax/i2400m/i2400m-usb.h
new file mode 100644
index 000000000000..6f76558b170f
--- /dev/null
+++ b/drivers/net/wimax/i2400m/i2400m-usb.h
@@ -0,0 +1,264 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * USB-specific i2400m driver definitions
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ * - Initial implementation
+ *
+ *
+ * This driver implements the bus-specific part of the i2400m for
+ * USB. Check i2400m.h for a generic driver description.
+ *
+ * ARCHITECTURE
+ *
+ * This driver listens to notifications sent from the notification
+ * endpoint (in usb-notif.c); when data is ready to read, the code in
+ * there schedules a read from the device (usb-rx.c) and then passes
+ * the data to the generic RX code (rx.c).
+ *
+ * When the generic driver needs to send data (network or control), it
+ * queues up in the TX FIFO (tx.c) and that will notify the driver
+ * through the i2400m->bus_tx_kick() callback
+ * (usb-tx.c:i2400mu_bus_tx_kick) which will send the items in the
+ * FIFO queue.
+ *
+ * This driver, as well, implements the USB-specific ops for the generic
+ * driver to be able to setup/teardown communication with the device
+ * [i2400m_bus_dev_start() and i2400m_bus_dev_stop()], reseting the
+ * device [i2400m_bus_reset()] and performing firmware upload
+ * [i2400m_bus_bm_cmd() and i2400_bus_bm_wait_for_ack()].
+ */
+
+#ifndef __I2400M_USB_H__
+#define __I2400M_USB_H__
+
+#include "i2400m.h"
+#include <linux/kthread.h>
+
+
+/*
+ * Error Density Count: cheapo error density (over time) counter
+ *
+ * Originally by Reinette Chatre <reinette.chatre@intel.com>
+ *
+ * Embed an 'struct edc' somewhere. Each time there is a soft or
+ * retryable error, call edc_inc() and check if the error top
+ * watermark has been reached.
+ */
+enum {
+ EDC_MAX_ERRORS = 10,
+ EDC_ERROR_TIMEFRAME = HZ,
+};
+
+/* error density counter */
+struct edc {
+ unsigned long timestart;
+ u16 errorcount;
+};
+
+static inline void edc_init(struct edc *edc)
+{
+ edc->timestart = jiffies;
+}
+
+/**
+ * edc_inc - report a soft error and check if we are over the watermark
+ *
+ * @edc: pointer to error density counter.
+ * @max_err: maximum number of errors we can accept over the timeframe
+ * @timeframe: lenght of the timeframe (in jiffies).
+ *
+ * Returns: !0 1 if maximum acceptable errors per timeframe has been
+ * exceeded. 0 otherwise.
+ *
+ * This is way to determine if the number of acceptable errors per time
+ * period has been exceeded. It is not accurate as there are cases in which
+ * this scheme will not work, for example if there are periodic occurences
+ * of errors that straddle updates to the start time. This scheme is
+ * sufficient for our usage.
+ *
+ * To use, embed a 'struct edc' somewhere, initialize it with
+ * edc_init() and when an error hits:
+ *
+ * if (do_something_fails_with_a_soft_error) {
+ * if (edc_inc(&my->edc, MAX_ERRORS, MAX_TIMEFRAME))
+ * Ops, hard error, do something about it
+ * else
+ * Retry or ignore, depending on whatever
+ * }
+ */
+static inline int edc_inc(struct edc *edc, u16 max_err, u16 timeframe)
+{
+ unsigned long now;
+
+ now = jiffies;
+ if (now - edc->timestart > timeframe) {
+ edc->errorcount = 1;
+ edc->timestart = now;
+ } else if (++edc->errorcount > max_err) {
+ edc->errorcount = 0;
+ edc->timestart = now;
+ return 1;
+ }
+ return 0;
+}
+
+/* Host-Device interface for USB */
+enum {
+ I2400MU_MAX_NOTIFICATION_LEN = 256,
+ I2400MU_BLK_SIZE = 16,
+ I2400MU_PL_SIZE_MAX = 0x3EFF,
+
+ /* Endpoints */
+ I2400MU_EP_BULK_OUT = 0,
+ I2400MU_EP_NOTIFICATION,
+ I2400MU_EP_RESET_COLD,
+ I2400MU_EP_BULK_IN,
+};
+
+
+/**
+ * struct i2400mu - descriptor for a USB connected i2400m
+ *
+ * @i2400m: bus-generic i2400m implementation; has to be first (see
+ * it's documentation in i2400m.h).
+ *
+ * @usb_dev: pointer to our USB device
+ *
+ * @usb_iface: pointer to our USB interface
+ *
+ * @urb_edc: error density counter; used to keep a density-on-time tab
+ * on how many soft (retryable or ignorable) errors we get. If we
+ * go over the threshold, we consider the bus transport is failing
+ * too much and reset.
+ *
+ * @notif_urb: URB for receiving notifications from the device.
+ *
+ * @tx_kthread: thread we use for data TX. We use a thread because in
+ * order to do deep power saving and put the device to sleep, we
+ * need to call usb_autopm_*() [blocking functions].
+ *
+ * @tx_wq: waitqueue for the TX kthread to sleep when there is no data
+ * to be sent; when more data is available, it is woken up by
+ * i2400mu_bus_tx_kick().
+ *
+ * @rx_kthread: thread we use for data RX. We use a thread because in
+ * order to do deep power saving and put the device to sleep, we
+ * need to call usb_autopm_*() [blocking functions].
+ *
+ * @rx_wq: waitqueue for the RX kthread to sleep when there is no data
+ * to receive. When data is available, it is woken up by
+ * usb-notif.c:i2400mu_notification_grok().
+ *
+ * @rx_pending_count: number of rx-data-ready notifications that were
+ * still not handled by the RX kthread.
+ *
+ * @rx_size: current RX buffer size that is being used.
+ *
+ * @rx_size_acc: accumulator of the sizes of the previous read
+ * transactions.
+ *
+ * @rx_size_cnt: number of read transactions accumulated in
+ * @rx_size_acc.
+ *
+ * @do_autopm: disable(0)/enable(>0) calling the
+ * usb_autopm_get/put_interface() barriers when executing
+ * commands. See doc in i2400mu_suspend() for more information.
+ *
+ * @rx_size_auto_shrink: if true, the rx_size is shrinked
+ * automatically based on the average size of the received
+ * transactions. This allows the receive code to allocate smaller
+ * chunks of memory and thus reduce pressure on the memory
+ * allocator by not wasting so much space. By default it is
+ * enabled.
+ *
+ * @debugfs_dentry: hookup for debugfs files.
+ * These have to be in a separate directory, a child of
+ * (wimax_dev->debugfs_dentry) so they can be removed when the
+ * module unloads, as we don't keep each dentry.
+ */
+struct i2400mu {
+ struct i2400m i2400m; /* FIRST! See doc */
+
+ struct usb_device *usb_dev;
+ struct usb_interface *usb_iface;
+ struct edc urb_edc; /* Error density counter */
+
+ struct urb *notif_urb;
+ struct task_struct *tx_kthread;
+ wait_queue_head_t tx_wq;
+
+ struct task_struct *rx_kthread;
+ wait_queue_head_t rx_wq;
+ atomic_t rx_pending_count;
+ size_t rx_size, rx_size_acc, rx_size_cnt;
+ atomic_t do_autopm;
+ u8 rx_size_auto_shrink;
+
+ struct dentry *debugfs_dentry;
+};
+
+
+static inline
+void i2400mu_init(struct i2400mu *i2400mu)
+{
+ i2400m_init(&i2400mu->i2400m);
+ edc_init(&i2400mu->urb_edc);
+ init_waitqueue_head(&i2400mu->tx_wq);
+ atomic_set(&i2400mu->rx_pending_count, 0);
+ init_waitqueue_head(&i2400mu->rx_wq);
+ i2400mu->rx_size = PAGE_SIZE - sizeof(struct skb_shared_info);
+ atomic_set(&i2400mu->do_autopm, 1);
+ i2400mu->rx_size_auto_shrink = 1;
+}
+
+extern int i2400mu_notification_setup(struct i2400mu *);
+extern void i2400mu_notification_release(struct i2400mu *);
+
+extern int i2400mu_rx_setup(struct i2400mu *);
+extern void i2400mu_rx_release(struct i2400mu *);
+extern void i2400mu_rx_kick(struct i2400mu *);
+
+extern int i2400mu_tx_setup(struct i2400mu *);
+extern void i2400mu_tx_release(struct i2400mu *);
+extern void i2400mu_bus_tx_kick(struct i2400m *);
+
+extern ssize_t i2400mu_bus_bm_cmd_send(struct i2400m *,
+ const struct i2400m_bootrom_header *,
+ size_t, int);
+extern ssize_t i2400mu_bus_bm_wait_for_ack(struct i2400m *,
+ struct i2400m_bootrom_header *,
+ size_t);
+#endif /* #ifndef __I2400M_USB_H__ */
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
new file mode 100644
index 000000000000..067c871cc226
--- /dev/null
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -0,0 +1,755 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Declarations for bus-generic internal APIs
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ * - Initial implementation
+ *
+ *
+ * GENERAL DRIVER ARCHITECTURE
+ *
+ * The i2400m driver is split in the following two major parts:
+ *
+ * - bus specific driver
+ * - bus generic driver (this part)
+ *
+ * The bus specific driver sets up stuff specific to the bus the
+ * device is connected to (USB, SDIO, PCI, tam-tam...non-authoritative
+ * nor binding list) which is basically the device-model management
+ * (probe/disconnect, etc), moving data from device to kernel and
+ * back, doing the power saving details and reseting the device.
+ *
+ * For details on each bus-specific driver, see it's include file,
+ * i2400m-BUSNAME.h
+ *
+ * The bus-generic functionality break up is:
+ *
+ * - Firmware upload: fw.c - takes care of uploading firmware to the
+ * device. bus-specific driver just needs to provides a way to
+ * execute boot-mode commands and to reset the device.
+ *
+ * - RX handling: rx.c - receives data from the bus-specific code and
+ * feeds it to the network or WiMAX stack or uses it to modify
+ * the driver state. bus-specific driver only has to receive
+ * frames and pass them to this module.
+ *
+ * - TX handling: tx.c - manages the TX FIFO queue and provides means
+ * for the bus-specific TX code to pull data from the FIFO
+ * queue. bus-specific code just pulls frames from this module
+ * to sends them to the device.
+ *
+ * - netdev glue: netdev.c - interface with Linux networking
+ * stack. Pass around data frames, and configure when the
+ * device is up and running or shutdown (through ifconfig up /
+ * down). Bus-generic only.
+ *
+ * - control ops: control.c - implements various commmands for
+ * controlling the device. bus-generic only.
+ *
+ * - device model glue: driver.c - implements helpers for the
+ * device-model glue done by the bus-specific layer
+ * (setup/release the driver resources), turning the device on
+ * and off, handling the device reboots/resets and a few simple
+ * WiMAX stack ops.
+ *
+ * Code is also broken up in linux-glue / device-glue.
+ *
+ * Linux glue contains functions that deal mostly with gluing with the
+ * rest of the Linux kernel.
+ *
+ * Device-glue are functions that deal mostly with the way the device
+ * does things and talk the device's language.
+ *
+ * device-glue code is licensed BSD so other open source OSes can take
+ * it to implement their drivers.
+ *
+ *
+ * APIs AND HEADER FILES
+ *
+ * This bus generic code exports three APIs:
+ *
+ * - HDI (host-device interface) definitions common to all busses
+ * (include/linux/wimax/i2400m.h); these can be also used by user
+ * space code.
+ * - internal API for the bus-generic code
+ * - external API for the bus-specific drivers
+ *
+ *
+ * LIFE CYCLE:
+ *
+ * When the bus-specific driver probes, it allocates a network device
+ * with enough space for it's data structue, that must contain a
+ * &struct i2400m at the top.
+ *
+ * On probe, it needs to fill the i2400m members marked as [fill], as
+ * well as i2400m->wimax_dev.net_dev and call i2400m_setup(). The
+ * i2400m driver will only register with the WiMAX and network stacks;
+ * the only access done to the device is to read the MAC address so we
+ * can register a network device. This calls i2400m_dev_start() to
+ * load firmware, setup communication with the device and configure it
+ * for operation.
+ *
+ * At this point, control and data communications are possible.
+ *
+ * On disconnect/driver unload, the bus-specific disconnect function
+ * calls i2400m_release() to undo i2400m_setup(). i2400m_dev_stop()
+ * shuts the firmware down and releases resources uses to communicate
+ * with the device.
+ *
+ * While the device is up, it might reset. The bus-specific driver has
+ * to catch that situation and call i2400m_dev_reset_handle() to deal
+ * with it (reset the internal driver structures and go back to square
+ * one).
+ */
+
+#ifndef __I2400M_H__
+#define __I2400M_H__
+
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <linux/completion.h>
+#include <linux/rwsem.h>
+#include <asm/atomic.h>
+#include <net/wimax.h>
+#include <linux/wimax/i2400m.h>
+#include <asm/byteorder.h>
+
+/* Misc constants */
+enum {
+ /* Firmware uploading */
+ I2400M_BOOT_RETRIES = 3,
+ /* Size of the Boot Mode Command buffer */
+ I2400M_BM_CMD_BUF_SIZE = 16 * 1024,
+ I2400M_BM_ACK_BUF_SIZE = 256,
+};
+
+
+/* Firmware version we request when pulling the fw image file */
+#define I2400M_FW_VERSION "1.3"
+
+
+/**
+ * i2400m_reset_type - methods to reset a device
+ *
+ * @I2400M_RT_WARM: Reset without device disconnection, device handles
+ * are kept valid but state is back to power on, with firmware
+ * re-uploaded.
+ * @I2400M_RT_COLD: Tell the device to disconnect itself from the bus
+ * and reconnect. Renders all device handles invalid.
+ * @I2400M_RT_BUS: Tells the bus to reset the device; last measure
+ * used when both types above don't work.
+ */
+enum i2400m_reset_type {
+ I2400M_RT_WARM, /* first measure */
+ I2400M_RT_COLD, /* second measure */
+ I2400M_RT_BUS, /* call in artillery */
+};
+
+struct i2400m_reset_ctx;
+
+/**
+ * struct i2400m - descriptor for an Intel 2400m
+ *
+ * Members marked with [fill] must be filled out/initialized before
+ * calling i2400m_setup().
+ *
+ * @bus_tx_block_size: [fill] SDIO imposes a 256 block size, USB 16,
+ * so we have a tx_blk_size variable that the bus layer sets to
+ * tell the engine how much of that we need.
+ *
+ * @bus_pl_size_max: [fill] Maximum payload size.
+ *
+ * @bus_dev_start: [fill] Function called by the bus-generic code
+ * [i2400m_dev_start()] to setup the bus-specific communications
+ * to the the device. See LIFE CYCLE above.
+ *
+ * NOTE: Doesn't need to upload the firmware, as that is taken
+ * care of by the bus-generic code.
+ *
+ * @bus_dev_stop: [fill] Function called by the bus-generic code
+ * [i2400m_dev_stop()] to shutdown the bus-specific communications
+ * to the the device. See LIFE CYCLE above.
+ *
+ * This function does not need to reset the device, just tear down
+ * all the host resources created to handle communication with
+ * the device.
+ *
+ * @bus_tx_kick: [fill] Function called by the bus-generic code to let
+ * the bus-specific code know that there is data available in the
+ * TX FIFO for transmission to the device.
+ *
+ * This function cannot sleep.
+ *
+ * @bus_reset: [fill] Function called by the bus-generic code to reset
+ * the device in in various ways. Doesn't need to wait for the
+ * reset to finish.
+ *
+ * If warm or cold reset fail, this function is expected to do a
+ * bus-specific reset (eg: USB reset) to get the device to a
+ * working state (even if it implies device disconecction).
+ *
+ * Note the warm reset is used by the firmware uploader to
+ * reinitialize the device.
+ *
+ * IMPORTANT: this is called very early in the device setup
+ * process, so it cannot rely on common infrastructure being laid
+ * out.
+ *
+ * @bus_bm_cmd_send: [fill] Function called to send a boot-mode
+ * command. Flags are defined in 'enum i2400m_bm_cmd_flags'. This
+ * is synchronous and has to return 0 if ok or < 0 errno code in
+ * any error condition.
+ *
+ * @bus_bm_wait_for_ack: [fill] Function called to wait for a
+ * boot-mode notification (that can be a response to a previously
+ * issued command or an asynchronous one). Will read until all the
+ * indicated size is read or timeout. Reading more or less data
+ * than asked for is an error condition. Return 0 if ok, < 0 errno
+ * code on error.
+ *
+ * The caller to this function will check if the response is a
+ * barker that indicates the device going into reset mode.
+ *
+ * @bus_fw_name: [fill] name of the firmware image (in most cases,
+ * they are all the same for a single release, except that they
+ * have the type of the bus embedded in the name (eg:
+ * i2400m-fw-X-VERSION.sbcf, where X is the bus name).
+ *
+ * @bus_bm_mac_addr_impaired: [fill] Set to true if the device's MAC
+ * address provided in boot mode is kind of broken and needs to
+ * be re-read later on.
+ *
+ *
+ * @wimax_dev: WiMAX generic device for linkage into the kernel WiMAX
+ * stack. Due to the way a net_device is allocated, we need to
+ * force this to be the first field so that we can get from
+ * netdev_priv() the right pointer.
+ *
+ * @state: device's state (as reported by it)
+ *
+ * @state_wq: waitqueue that is woken up whenever the state changes
+ *
+ * @tx_lock: spinlock to protect TX members
+ *
+ * @tx_buf: FIFO buffer for TX; we queue data here
+ *
+ * @tx_in: FIFO index for incoming data. Note this doesn't wrap around
+ * and it is always greater than @tx_out.
+ *
+ * @tx_out: FIFO index for outgoing data
+ *
+ * @tx_msg: current TX message that is active in the FIFO for
+ * appending payloads.
+ *
+ * @tx_sequence: current sequence number for TX messages from the
+ * device to the host.
+ *
+ * @tx_msg_size: size of the current message being transmitted by the
+ * bus-specific code.
+ *
+ * @tx_pl_num: total number of payloads sent
+ *
+ * @tx_pl_max: maximum number of payloads sent in a TX message
+ *
+ * @tx_pl_min: minimum number of payloads sent in a TX message
+ *
+ * @tx_num: number of TX messages sent
+ *
+ * @tx_size_acc: number of bytes in all TX messages sent
+ * (this is different to net_dev's statistics as it also counts
+ * control messages).
+ *
+ * @tx_size_min: smallest TX message sent.
+ *
+ * @tx_size_max: biggest TX message sent.
+ *
+ * @rx_lock: spinlock to protect RX members
+ *
+ * @rx_pl_num: total number of payloads received
+ *
+ * @rx_pl_max: maximum number of payloads received in a RX message
+ *
+ * @rx_pl_min: minimum number of payloads received in a RX message
+ *
+ * @rx_num: number of RX messages received
+ *
+ * @rx_size_acc: number of bytes in all RX messages received
+ * (this is different to net_dev's statistics as it also counts
+ * control messages).
+ *
+ * @rx_size_min: smallest RX message received.
+ *
+ * @rx_size_max: buggest RX message received.
+ *
+ * @init_mutex: Mutex used for serializing the device bringup
+ * sequence; this way if the device reboots in the middle, we
+ * don't try to do a bringup again while we are tearing down the
+ * one that failed.
+ *
+ * Can't reuse @msg_mutex because from within the bringup sequence
+ * we need to send messages to the device and thus use @msg_mutex.
+ *
+ * @msg_mutex: mutex used to send control commands to the device (we
+ * only allow one at a time, per host-device interface design).
+ *
+ * @msg_completion: used to wait for an ack to a control command sent
+ * to the device.
+ *
+ * @ack_skb: used to store the actual ack to a control command if the
+ * reception of the command was successful. Otherwise, a ERR_PTR()
+ * errno code that indicates what failed with the ack reception.
+ *
+ * Only valid after @msg_completion is woken up. Only updateable
+ * if @msg_completion is armed. Only touched by
+ * i2400m_msg_to_dev().
+ *
+ * Protected by @rx_lock. In theory the command execution flow is
+ * sequential, but in case the device sends an out-of-phase or
+ * very delayed response, we need to avoid it trampling current
+ * execution.
+ *
+ * @bm_cmd_buf: boot mode command buffer for composing firmware upload
+ * commands.
+ *
+ * USB can't r/w to stack, vmalloc, etc...as well, we end up
+ * having to alloc/free a lot to compose commands, so we use these
+ * for stagging and not having to realloc all the time.
+ *
+ * This assumes the code always runs serialized. Only one thread
+ * can call i2400m_bm_cmd() at the same time.
+ *
+ * @bm_ack_buf: boot mode acknoledge buffer for staging reception of
+ * responses to commands.
+ *
+ * See @bm_cmd_buf.
+ *
+ * @work_queue: work queue for processing device reports. This
+ * workqueue cannot be used for processing TX or RX to the device,
+ * as from it we'll process device reports, which might require
+ * further communication with the device.
+ *
+ * @debugfs_dentry: hookup for debugfs files.
+ * These have to be in a separate directory, a child of
+ * (wimax_dev->debugfs_dentry) so they can be removed when the
+ * module unloads, as we don't keep each dentry.
+ */
+struct i2400m {
+ struct wimax_dev wimax_dev; /* FIRST! See doc */
+
+ unsigned updown:1; /* Network device is up or down */
+ unsigned boot_mode:1; /* is the device in boot mode? */
+ unsigned sboot:1; /* signed or unsigned fw boot */
+ unsigned ready:1; /* all probing steps done */
+ u8 trace_msg_from_user; /* echo rx msgs to 'trace' pipe */
+ /* typed u8 so debugfs/u8 can tweak */
+ enum i2400m_system_state state;
+ wait_queue_head_t state_wq; /* Woken up when on state updates */
+
+ size_t bus_tx_block_size;
+ size_t bus_pl_size_max;
+ int (*bus_dev_start)(struct i2400m *);
+ void (*bus_dev_stop)(struct i2400m *);
+ void (*bus_tx_kick)(struct i2400m *);
+ int (*bus_reset)(struct i2400m *, enum i2400m_reset_type);
+ ssize_t (*bus_bm_cmd_send)(struct i2400m *,
+ const struct i2400m_bootrom_header *,
+ size_t, int flags);
+ ssize_t (*bus_bm_wait_for_ack)(struct i2400m *,
+ struct i2400m_bootrom_header *, size_t);
+ const char *bus_fw_name;
+ unsigned bus_bm_mac_addr_impaired:1;
+
+ spinlock_t tx_lock; /* protect TX state */
+ void *tx_buf;
+ size_t tx_in, tx_out;
+ struct i2400m_msg_hdr *tx_msg;
+ size_t tx_sequence, tx_msg_size;
+ /* TX stats */
+ unsigned tx_pl_num, tx_pl_max, tx_pl_min,
+ tx_num, tx_size_acc, tx_size_min, tx_size_max;
+
+ /* RX stats */
+ spinlock_t rx_lock; /* protect RX state */
+ unsigned rx_pl_num, rx_pl_max, rx_pl_min,
+ rx_num, rx_size_acc, rx_size_min, rx_size_max;
+
+ struct mutex msg_mutex; /* serialize command execution */
+ struct completion msg_completion;
+ struct sk_buff *ack_skb; /* protected by rx_lock */
+
+ void *bm_ack_buf; /* for receiving acks over USB */
+ void *bm_cmd_buf; /* for issuing commands over USB */
+
+ struct workqueue_struct *work_queue;
+
+ struct mutex init_mutex; /* protect bringup seq */
+ struct i2400m_reset_ctx *reset_ctx; /* protected by init_mutex */
+
+ struct work_struct wake_tx_ws;
+ struct sk_buff *wake_tx_skb;
+
+ struct dentry *debugfs_dentry;
+};
+
+
+/*
+ * Initialize a 'struct i2400m' from all zeroes
+ *
+ * This is a bus-generic API call.
+ */
+static inline
+void i2400m_init(struct i2400m *i2400m)
+{
+ wimax_dev_init(&i2400m->wimax_dev);
+
+ i2400m->boot_mode = 1;
+ init_waitqueue_head(&i2400m->state_wq);
+
+ spin_lock_init(&i2400m->tx_lock);
+ i2400m->tx_pl_min = UINT_MAX;
+ i2400m->tx_size_min = UINT_MAX;
+
+ spin_lock_init(&i2400m->rx_lock);
+ i2400m->rx_pl_min = UINT_MAX;
+ i2400m->rx_size_min = UINT_MAX;
+
+ mutex_init(&i2400m->msg_mutex);
+ init_completion(&i2400m->msg_completion);
+
+ mutex_init(&i2400m->init_mutex);
+ /* wake_tx_ws is initialized in i2400m_tx_setup() */
+}
+
+
+/*
+ * Bus-generic internal APIs
+ * -------------------------
+ */
+
+static inline
+struct i2400m *wimax_dev_to_i2400m(struct wimax_dev *wimax_dev)
+{
+ return container_of(wimax_dev, struct i2400m, wimax_dev);
+}
+
+static inline
+struct i2400m *net_dev_to_i2400m(struct net_device *net_dev)
+{
+ return wimax_dev_to_i2400m(netdev_priv(net_dev));
+}
+
+/*
+ * Boot mode support
+ */
+
+/**
+ * i2400m_bm_cmd_flags - flags to i2400m_bm_cmd()
+ *
+ * @I2400M_BM_CMD_RAW: send the command block as-is, without doing any
+ * extra processing for adding CRC.
+ */
+enum i2400m_bm_cmd_flags {
+ I2400M_BM_CMD_RAW = 1 << 2,
+};
+
+/**
+ * i2400m_bri - Boot-ROM indicators
+ *
+ * Flags for i2400m_bootrom_init() and i2400m_dev_bootstrap() [which
+ * are passed from things like i2400m_setup()]. Can be combined with
+ * |.
+ *
+ * @I2400M_BRI_SOFT: The device rebooted already and a reboot
+ * barker received, proceed directly to ack the boot sequence.
+ * @I2400M_BRI_NO_REBOOT: Do not reboot the device and proceed
+ * directly to wait for a reboot barker from the device.
+ * @I2400M_BRI_MAC_REINIT: We need to reinitialize the boot
+ * rom after reading the MAC adress. This is quite a dirty hack,
+ * if you ask me -- the device requires the bootrom to be
+ * intialized after reading the MAC address.
+ */
+enum i2400m_bri {
+ I2400M_BRI_SOFT = 1 << 1,
+ I2400M_BRI_NO_REBOOT = 1 << 2,
+ I2400M_BRI_MAC_REINIT = 1 << 3,
+};
+
+extern void i2400m_bm_cmd_prepare(struct i2400m_bootrom_header *);
+extern int i2400m_dev_bootstrap(struct i2400m *, enum i2400m_bri);
+extern int i2400m_read_mac_addr(struct i2400m *);
+extern int i2400m_bootrom_init(struct i2400m *, enum i2400m_bri);
+
+/* Make/grok boot-rom header commands */
+
+static inline
+__le32 i2400m_brh_command(enum i2400m_brh_opcode opcode, unsigned use_checksum,
+ unsigned direct_access)
+{
+ return cpu_to_le32(
+ I2400M_BRH_SIGNATURE
+ | (direct_access ? I2400M_BRH_DIRECT_ACCESS : 0)
+ | I2400M_BRH_RESPONSE_REQUIRED /* response always required */
+ | (use_checksum ? I2400M_BRH_USE_CHECKSUM : 0)
+ | (opcode & I2400M_BRH_OPCODE_MASK));
+}
+
+static inline
+void i2400m_brh_set_opcode(struct i2400m_bootrom_header *hdr,
+ enum i2400m_brh_opcode opcode)
+{
+ hdr->command = cpu_to_le32(
+ (le32_to_cpu(hdr->command) & ~I2400M_BRH_OPCODE_MASK)
+ | (opcode & I2400M_BRH_OPCODE_MASK));
+}
+
+static inline
+unsigned i2400m_brh_get_opcode(const struct i2400m_bootrom_header *hdr)
+{
+ return le32_to_cpu(hdr->command) & I2400M_BRH_OPCODE_MASK;
+}
+
+static inline
+unsigned i2400m_brh_get_response(const struct i2400m_bootrom_header *hdr)
+{
+ return (le32_to_cpu(hdr->command) & I2400M_BRH_RESPONSE_MASK)
+ >> I2400M_BRH_RESPONSE_SHIFT;
+}
+
+static inline
+unsigned i2400m_brh_get_use_checksum(const struct i2400m_bootrom_header *hdr)
+{
+ return le32_to_cpu(hdr->command) & I2400M_BRH_USE_CHECKSUM;
+}
+
+static inline
+unsigned i2400m_brh_get_response_required(
+ const struct i2400m_bootrom_header *hdr)
+{
+ return le32_to_cpu(hdr->command) & I2400M_BRH_RESPONSE_REQUIRED;
+}
+
+static inline
+unsigned i2400m_brh_get_direct_access(const struct i2400m_bootrom_header *hdr)
+{
+ return le32_to_cpu(hdr->command) & I2400M_BRH_DIRECT_ACCESS;
+}
+
+static inline
+unsigned i2400m_brh_get_signature(const struct i2400m_bootrom_header *hdr)
+{
+ return (le32_to_cpu(hdr->command) & I2400M_BRH_SIGNATURE_MASK)
+ >> I2400M_BRH_SIGNATURE_SHIFT;
+}
+
+
+/*
+ * Driver / device setup and internal functions
+ */
+extern void i2400m_netdev_setup(struct net_device *net_dev);
+extern int i2400m_tx_setup(struct i2400m *);
+extern void i2400m_wake_tx_work(struct work_struct *);
+extern void i2400m_tx_release(struct i2400m *);
+
+extern void i2400m_net_rx(struct i2400m *, struct sk_buff *, unsigned,
+ const void *, int);
+enum i2400m_pt;
+extern int i2400m_tx(struct i2400m *, const void *, size_t, enum i2400m_pt);
+
+#ifdef CONFIG_DEBUG_FS
+extern int i2400m_debugfs_add(struct i2400m *);
+extern void i2400m_debugfs_rm(struct i2400m *);
+#else
+static inline int i2400m_debugfs_add(struct i2400m *i2400m)
+{
+ return 0;
+}
+static inline void i2400m_debugfs_rm(struct i2400m *i2400m) {}
+#endif
+
+/* Called by _dev_start()/_dev_stop() to initialize the device itself */
+extern int i2400m_dev_initialize(struct i2400m *);
+extern void i2400m_dev_shutdown(struct i2400m *);
+
+extern struct attribute_group i2400m_dev_attr_group;
+
+extern int i2400m_schedule_work(struct i2400m *,
+ void (*)(struct work_struct *), gfp_t);
+
+/* HDI message's payload description handling */
+
+static inline
+size_t i2400m_pld_size(const struct i2400m_pld *pld)
+{
+ return I2400M_PLD_SIZE_MASK & le32_to_cpu(pld->val);
+}
+
+static inline
+enum i2400m_pt i2400m_pld_type(const struct i2400m_pld *pld)
+{
+ return (I2400M_PLD_TYPE_MASK & le32_to_cpu(pld->val))
+ >> I2400M_PLD_TYPE_SHIFT;
+}
+
+static inline
+void i2400m_pld_set(struct i2400m_pld *pld, size_t size,
+ enum i2400m_pt type)
+{
+ pld->val = cpu_to_le32(
+ ((type << I2400M_PLD_TYPE_SHIFT) & I2400M_PLD_TYPE_MASK)
+ | (size & I2400M_PLD_SIZE_MASK));
+}
+
+
+/*
+ * API for the bus-specific drivers
+ * --------------------------------
+ */
+
+static inline
+struct i2400m *i2400m_get(struct i2400m *i2400m)
+{
+ dev_hold(i2400m->wimax_dev.net_dev);
+ return i2400m;
+}
+
+static inline
+void i2400m_put(struct i2400m *i2400m)
+{
+ dev_put(i2400m->wimax_dev.net_dev);
+}
+
+extern int i2400m_dev_reset_handle(struct i2400m *);
+
+/*
+ * _setup()/_release() are called by the probe/disconnect functions of
+ * the bus-specific drivers.
+ */
+extern int i2400m_setup(struct i2400m *, enum i2400m_bri bm_flags);
+extern void i2400m_release(struct i2400m *);
+
+extern int i2400m_rx(struct i2400m *, struct sk_buff *);
+extern struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *, size_t *);
+extern void i2400m_tx_msg_sent(struct i2400m *);
+
+static const __le32 i2400m_NBOOT_BARKER[4] = {
+ __constant_cpu_to_le32(I2400M_NBOOT_BARKER),
+ __constant_cpu_to_le32(I2400M_NBOOT_BARKER),
+ __constant_cpu_to_le32(I2400M_NBOOT_BARKER),
+ __constant_cpu_to_le32(I2400M_NBOOT_BARKER)
+};
+
+static const __le32 i2400m_SBOOT_BARKER[4] = {
+ __constant_cpu_to_le32(I2400M_SBOOT_BARKER),
+ __constant_cpu_to_le32(I2400M_SBOOT_BARKER),
+ __constant_cpu_to_le32(I2400M_SBOOT_BARKER),
+ __constant_cpu_to_le32(I2400M_SBOOT_BARKER)
+};
+
+
+/*
+ * Utility functions
+ */
+
+static inline
+struct device *i2400m_dev(struct i2400m *i2400m)
+{
+ return i2400m->wimax_dev.net_dev->dev.parent;
+}
+
+/*
+ * Helper for scheduling simple work functions
+ *
+ * This struct can get any kind of payload attached (normally in the
+ * form of a struct where you pack the stuff you want to pass to the
+ * _work function).
+ */
+struct i2400m_work {
+ struct work_struct ws;
+ struct i2400m *i2400m;
+ u8 pl[0];
+};
+extern int i2400m_queue_work(struct i2400m *,
+ void (*)(struct work_struct *), gfp_t,
+ const void *, size_t);
+
+extern int i2400m_msg_check_status(const struct i2400m_l3l4_hdr *,
+ char *, size_t);
+extern int i2400m_msg_size_check(struct i2400m *,
+ const struct i2400m_l3l4_hdr *, size_t);
+extern struct sk_buff *i2400m_msg_to_dev(struct i2400m *, const void *, size_t);
+extern void i2400m_msg_to_dev_cancel_wait(struct i2400m *, int);
+extern void i2400m_msg_ack_hook(struct i2400m *,
+ const struct i2400m_l3l4_hdr *, size_t);
+extern void i2400m_report_hook(struct i2400m *,
+ const struct i2400m_l3l4_hdr *, size_t);
+extern int i2400m_cmd_enter_powersave(struct i2400m *);
+extern int i2400m_cmd_get_state(struct i2400m *);
+extern int i2400m_cmd_exit_idle(struct i2400m *);
+extern struct sk_buff *i2400m_get_device_info(struct i2400m *);
+extern int i2400m_firmware_check(struct i2400m *);
+extern int i2400m_set_init_config(struct i2400m *,
+ const struct i2400m_tlv_hdr **, size_t);
+
+static inline
+struct usb_endpoint_descriptor *usb_get_epd(struct usb_interface *iface, int ep)
+{
+ return &iface->cur_altsetting->endpoint[ep].desc;
+}
+
+extern int i2400m_op_rfkill_sw_toggle(struct wimax_dev *,
+ enum wimax_rf_state);
+extern void i2400m_report_tlv_rf_switches_status(
+ struct i2400m *, const struct i2400m_tlv_rf_switches_status *);
+
+
+/*
+ * Do a millisecond-sleep for allowing wireshark to dump all the data
+ * packets. Used only for debugging.
+ */
+static inline
+void __i2400m_msleep(unsigned ms)
+{
+#if 1
+#else
+ msleep(ms);
+#endif
+}
+
+/* Module parameters */
+
+extern int i2400m_idle_mode_disabled;
+
+
+#endif /* #ifndef __I2400M_H__ */
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
new file mode 100644
index 000000000000..63fe708e8a31
--- /dev/null
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -0,0 +1,524 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Glue with the networking stack
+ *
+ *
+ * Copyright (C) 2007 Intel Corporation <linux-wimax@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This 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.
+ *
+ *
+ * This implements an ethernet device for the i2400m.
+ *
+ * We fake being an ethernet device to simplify the support from user
+ * space and from the other side. The world is (sadly) configured to
+ * take in only Ethernet devices...
+ *
+ * Because of this, currently there is an copy-each-rxed-packet
+ * overhead on the RX path. Each IP packet has to be reallocated to
+ * add an ethernet header (as there is no space in what we get from
+ * the device). This is a known drawback and coming versions of the
+ * device's firmware are being changed to add header space that can be
+ * used to insert the ethernet header without having to reallocate and
+ * copy.
+ *
+ * TX error handling is tricky; because we have to FIFO/queue the
+ * buffers for transmission (as the hardware likes it aggregated), we
+ * just give the skb to the TX subsystem and by the time it is
+ * transmitted, we have long forgotten about it. So we just don't care
+ * too much about it.
+ *
+ * Note that when the device is in idle mode with the basestation, we
+ * need to negotiate coming back up online. That involves negotiation
+ * and possible user space interaction. Thus, we defer to a workqueue
+ * to do all that. By default, we only queue a single packet and drop
+ * the rest, as potentially the time to go back from idle to normal is
+ * long.
+ *
+ * ROADMAP
+ *
+ * i2400m_open Called on ifconfig up
+ * i2400m_stop Called on ifconfig down
+ *
+ * i2400m_hard_start_xmit Called by the network stack to send a packet
+ * i2400m_net_wake_tx Wake up device from basestation-IDLE & TX
+ * i2400m_wake_tx_work
+ * i2400m_cmd_exit_idle
+ * i2400m_tx
+ * i2400m_net_tx TX a data frame
+ * i2400m_tx
+ *
+ * i2400m_change_mtu Called on ifconfig mtu XXX
+ *
+ * i2400m_tx_timeout Called when the device times out
+ *
+ * i2400m_net_rx Called by the RX code when a data frame is
+ * available.
+ * i2400m_netdev_setup Called to setup all the netdev stuff from
+ * alloc_netdev.
+ */
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include "i2400m.h"
+
+
+#define D_SUBMODULE netdev
+#include "debug-levels.h"
+
+enum {
+/* netdev interface */
+ /*
+ * Out of NWG spec (R1_v1.2.2), 3.3.3 ASN Bearer Plane MTU Size
+ *
+ * The MTU is 1400 or less
+ */
+ I2400M_MAX_MTU = 1400,
+ I2400M_TX_TIMEOUT = HZ,
+ I2400M_TX_QLEN = 5,
+};
+
+
+static
+int i2400m_open(struct net_device *net_dev)
+{
+ int result;
+ struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
+ struct device *dev = i2400m_dev(i2400m);
+
+ d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m);
+ if (i2400m->ready == 0) {
+ dev_err(dev, "Device is still initializing\n");
+ result = -EBUSY;
+ } else
+ result = 0;
+ d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n",
+ net_dev, i2400m, result);
+ return result;
+}
+
+
+/*
+ *
+ * On kernel versions where cancel_work_sync() didn't return anything,
+ * we rely on wake_tx_skb() being non-NULL.
+ */
+static
+int i2400m_stop(struct net_device *net_dev)
+{
+ struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
+ struct device *dev = i2400m_dev(i2400m);
+
+ d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m);
+ /* See i2400m_hard_start_xmit(), references are taken there
+ * and here we release them if the work was still
+ * pending. Note we can't differentiate work not pending vs
+ * never scheduled, so the NULL check does that. */
+ if (cancel_work_sync(&i2400m->wake_tx_ws) == 0
+ && i2400m->wake_tx_skb != NULL) {
+ unsigned long flags;
+ struct sk_buff *wake_tx_skb;
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
+ wake_tx_skb = i2400m->wake_tx_skb; /* compat help */
+ i2400m->wake_tx_skb = NULL; /* compat help */
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+ i2400m_put(i2400m);
+ kfree_skb(wake_tx_skb);
+ }
+ d_fnend(3, dev, "(net_dev %p [i2400m %p]) = 0\n", net_dev, i2400m);
+ return 0;
+}
+
+
+/*
+ * Wake up the device and transmit a held SKB, then restart the net queue
+ *
+ * When the device goes into basestation-idle mode, we need to tell it
+ * to exit that mode; it will negotiate with the base station, user
+ * space may have to intervene to rehandshake crypto and then tell us
+ * when it is ready to transmit the packet we have "queued". Still we
+ * need to give it sometime after it reports being ok.
+ *
+ * On error, there is not much we can do. If the error was on TX, we
+ * still wake the queue up to see if the next packet will be luckier.
+ *
+ * If _cmd_exit_idle() fails...well, it could be many things; most
+ * commonly it is that something else took the device out of IDLE mode
+ * (for example, the base station). In that case we get an -EILSEQ and
+ * we are just going to ignore that one. If the device is back to
+ * connected, then fine -- if it is someother state, the packet will
+ * be dropped anyway.
+ */
+void i2400m_wake_tx_work(struct work_struct *ws)
+{
+ int result;
+ struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws);
+ struct device *dev = i2400m_dev(i2400m);
+ struct sk_buff *skb = i2400m->wake_tx_skb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
+ skb = i2400m->wake_tx_skb;
+ i2400m->wake_tx_skb = NULL;
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+
+ d_fnstart(3, dev, "(ws %p i2400m %p skb %p)\n", ws, i2400m, skb);
+ result = -EINVAL;
+ if (skb == NULL) {
+ dev_err(dev, "WAKE&TX: skb dissapeared!\n");
+ goto out_put;
+ }
+ result = i2400m_cmd_exit_idle(i2400m);
+ if (result == -EILSEQ)
+ result = 0;
+ if (result < 0) {
+ dev_err(dev, "WAKE&TX: device didn't get out of idle: "
+ "%d\n", result);
+ goto error;
+ }
+ result = wait_event_timeout(i2400m->state_wq,
+ i2400m->state != I2400M_SS_IDLE, 5 * HZ);
+ if (result == 0)
+ result = -ETIMEDOUT;
+ if (result < 0) {
+ dev_err(dev, "WAKE&TX: error waiting for device to exit IDLE: "
+ "%d\n", result);
+ goto error;
+ }
+ msleep(20); /* device still needs some time or it drops it */
+ result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA);
+ netif_wake_queue(i2400m->wimax_dev.net_dev);
+error:
+ kfree_skb(skb); /* refcount transferred by _hard_start_xmit() */
+out_put:
+ i2400m_put(i2400m);
+ d_fnend(3, dev, "(ws %p i2400m %p skb %p) = void [%d]\n",
+ ws, i2400m, skb, result);
+}
+
+
+/*
+ * Prepare the data payload TX header
+ *
+ * The i2400m expects a 4 byte header in front of a data packet.
+ *
+ * Because we pretend to be an ethernet device, this packet comes with
+ * an ethernet header. Pull it and push our header.
+ */
+static
+void i2400m_tx_prep_header(struct sk_buff *skb)
+{
+ struct i2400m_pl_data_hdr *pl_hdr;
+ skb_pull(skb, ETH_HLEN);
+ pl_hdr = (struct i2400m_pl_data_hdr *) skb_push(skb, sizeof(*pl_hdr));
+ pl_hdr->reserved = 0;
+}
+
+
+/*
+ * TX an skb to an idle device
+ *
+ * When the device is in basestation-idle mode, we need to wake it up
+ * and then TX. So we queue a work_struct for doing so.
+ *
+ * We need to get an extra ref for the skb (so it is not dropped), as
+ * well as be careful not to queue more than one request (won't help
+ * at all). If more than one request comes or there are errors, we
+ * just drop the packets (see i2400m_hard_start_xmit()).
+ */
+static
+int i2400m_net_wake_tx(struct i2400m *i2400m, struct net_device *net_dev,
+ struct sk_buff *skb)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ unsigned long flags;
+
+ d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev);
+ if (net_ratelimit()) {
+ d_printf(3, dev, "WAKE&NETTX: "
+ "skb %p sending %d bytes to radio\n",
+ skb, skb->len);
+ d_dump(4, dev, skb->data, skb->len);
+ }
+ /* We hold a ref count for i2400m and skb, so when
+ * stopping() the device, we need to cancel that work
+ * and if pending, release those resources. */
+ result = 0;
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
+ if (!work_pending(&i2400m->wake_tx_ws)) {
+ netif_stop_queue(net_dev);
+ i2400m_get(i2400m);
+ i2400m->wake_tx_skb = skb_get(skb); /* transfer ref count */
+ i2400m_tx_prep_header(skb);
+ result = schedule_work(&i2400m->wake_tx_ws);
+ WARN_ON(result == 0);
+ }
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+ if (result == 0) {
+ /* Yes, this happens even if we stopped the
+ * queue -- blame the queue disciplines that
+ * queue without looking -- I guess there is a reason
+ * for that. */
+ if (net_ratelimit())
+ d_printf(1, dev, "NETTX: device exiting idle, "
+ "dropping skb %p, queue running %d\n",
+ skb, netif_queue_stopped(net_dev));
+ result = -EBUSY;
+ }
+ d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result);
+ return result;
+}
+
+
+/*
+ * Transmit a packet to the base station on behalf of the network stack.
+ *
+ * Returns: 0 if ok, < 0 errno code on error.
+ *
+ * We need to pull the ethernet header and add the hardware header,
+ * which is currently set to all zeroes and reserved.
+ */
+static
+int i2400m_net_tx(struct i2400m *i2400m, struct net_device *net_dev,
+ struct sk_buff *skb)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+
+ d_fnstart(3, dev, "(i2400m %p net_dev %p skb %p)\n",
+ i2400m, net_dev, skb);
+ /* FIXME: check eth hdr, only IPv4 is routed by the device as of now */
+ net_dev->trans_start = jiffies;
+ i2400m_tx_prep_header(skb);
+ d_printf(3, dev, "NETTX: skb %p sending %d bytes to radio\n",
+ skb, skb->len);
+ d_dump(4, dev, skb->data, skb->len);
+ result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA);
+ d_fnend(3, dev, "(i2400m %p net_dev %p skb %p) = %d\n",
+ i2400m, net_dev, skb, result);
+ return result;
+}
+
+
+/*
+ * Transmit a packet to the base station on behalf of the network stack
+ *
+ *
+ * Returns: NETDEV_TX_OK (always, even in case of error)
+ *
+ * In case of error, we just drop it. Reasons:
+ *
+ * - we add a hw header to each skb, and if the network stack
+ * retries, we have no way to know if that skb has it or not.
+ *
+ * - network protocols have their own drop-recovery mechanisms
+ *
+ * - there is not much else we can do
+ *
+ * If the device is idle, we need to wake it up; that is an operation
+ * that will sleep. See i2400m_net_wake_tx() for details.
+ */
+static
+int i2400m_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *net_dev)
+{
+ int result;
+ struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
+ struct device *dev = i2400m_dev(i2400m);
+
+ d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev);
+ if (i2400m->state == I2400M_SS_IDLE)
+ result = i2400m_net_wake_tx(i2400m, net_dev, skb);
+ else
+ result = i2400m_net_tx(i2400m, net_dev, skb);
+ if (result < 0)
+ net_dev->stats.tx_dropped++;
+ else {
+ net_dev->stats.tx_packets++;
+ net_dev->stats.tx_bytes += skb->len;
+ }
+ kfree_skb(skb);
+ result = NETDEV_TX_OK;
+ d_fnend(3, dev, "(skb %p net_dev %p) = %d\n", skb, net_dev, result);
+ return result;
+}
+
+
+static
+int i2400m_change_mtu(struct net_device *net_dev, int new_mtu)
+{
+ int result;
+ struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
+ struct device *dev = i2400m_dev(i2400m);
+
+ if (new_mtu >= I2400M_MAX_MTU) {
+ dev_err(dev, "Cannot change MTU to %d (max is %d)\n",
+ new_mtu, I2400M_MAX_MTU);
+ result = -EINVAL;
+ } else {
+ net_dev->mtu = new_mtu;
+ result = 0;
+ }
+ return result;
+}
+
+
+static
+void i2400m_tx_timeout(struct net_device *net_dev)
+{
+ /*
+ * We might want to kick the device
+ *
+ * There is not much we can do though, as the device requires
+ * that we send the data aggregated. By the time we receive
+ * this, there might be data pending to be sent or not...
+ */
+ net_dev->stats.tx_errors++;
+ return;
+}
+
+
+/*
+ * Create a fake ethernet header
+ *
+ * For emulating an ethernet device, every received IP header has to
+ * be prefixed with an ethernet header.
+ *
+ * What we receive has (potentially) many IP packets concatenated with
+ * no ETH_HLEN bytes prefixed. Thus there is no space for an eth
+ * header.
+ *
+ * We would have to reallocate or do ugly fragment tricks in order to
+ * add it.
+ *
+ * But what we do is use the header space of the RX transaction
+ * (*msg_hdr) as we don't need it anymore; then we'll point all the
+ * data skbs there, as they share the same backing store.
+ *
+ * We only support IPv4 for v3 firmware.
+ */
+static
+void i2400m_rx_fake_eth_header(struct net_device *net_dev,
+ void *_eth_hdr)
+{
+ struct ethhdr *eth_hdr = _eth_hdr;
+
+ memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest));
+ memset(eth_hdr->h_source, 0, sizeof(eth_hdr->h_dest));
+ eth_hdr->h_proto = __constant_cpu_to_be16(ETH_P_IP);
+}
+
+
+/*
+ * i2400m_net_rx - pass a network packet to the stack
+ *
+ * @i2400m: device instance
+ * @skb_rx: the skb where the buffer pointed to by @buf is
+ * @i: 1 if payload is the only one
+ * @buf: pointer to the buffer containing the data
+ * @len: buffer's length
+ *
+ * We just clone the skb and set it up so that it's skb->data pointer
+ * points to "buf" and it's length.
+ *
+ * Note that if the payload is the last (or the only one) in a
+ * multi-payload message, we don't clone the SKB but just reuse it.
+ *
+ * This function is normally run from a thread context. However, we
+ * still use netif_rx() instead of netif_receive_skb() as was
+ * recommended in the mailing list. Reason is in some stress tests
+ * when sending/receiving a lot of data we seem to hit a softlock in
+ * the kernel's TCP implementation [aroudn tcp_delay_timer()]. Using
+ * netif_rx() took care of the issue.
+ *
+ * This is, of course, still open to do more research on why running
+ * with netif_receive_skb() hits this softlock. FIXME.
+ *
+ * FIXME: currently we don't do any efforts at distinguishing if what
+ * we got was an IPv4 or IPv6 header, to setup the protocol field
+ * correctly.
+ */
+void i2400m_net_rx(struct i2400m *i2400m, struct sk_buff *skb_rx,
+ unsigned i, const void *buf, int buf_len)
+{
+ struct net_device *net_dev = i2400m->wimax_dev.net_dev;
+ struct device *dev = i2400m_dev(i2400m);
+ struct sk_buff *skb;
+
+ d_fnstart(2, dev, "(i2400m %p buf %p buf_len %d)\n",
+ i2400m, buf, buf_len);
+ if (i) {
+ skb = skb_get(skb_rx);
+ d_printf(2, dev, "RX: reusing first payload skb %p\n", skb);
+ skb_pull(skb, buf - (void *) skb->data);
+ skb_trim(skb, (void *) skb_end_pointer(skb) - buf);
+ } else {
+ /* Yes, this is bad -- a lot of overhead -- see
+ * comments at the top of the file */
+ skb = __netdev_alloc_skb(net_dev, buf_len, GFP_KERNEL);
+ if (skb == NULL) {
+ dev_err(dev, "NETRX: no memory to realloc skb\n");
+ net_dev->stats.rx_dropped++;
+ goto error_skb_realloc;
+ }
+ memcpy(skb_put(skb, buf_len), buf, buf_len);
+ }
+ i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev,
+ skb->data - ETH_HLEN);
+ skb_set_mac_header(skb, -ETH_HLEN);
+ skb->dev = i2400m->wimax_dev.net_dev;
+ skb->protocol = htons(ETH_P_IP);
+ net_dev->stats.rx_packets++;
+ net_dev->stats.rx_bytes += buf_len;
+ d_printf(3, dev, "NETRX: receiving %d bytes to network stack\n",
+ buf_len);
+ d_dump(4, dev, buf, buf_len);
+ netif_rx_ni(skb); /* see notes in function header */
+error_skb_realloc:
+ d_fnend(2, dev, "(i2400m %p buf %p buf_len %d) = void\n",
+ i2400m, buf, buf_len);
+}
+
+
+/**
+ * i2400m_netdev_setup - Setup setup @net_dev's i2400m private data
+ *
+ * Called by alloc_netdev()
+ */
+void i2400m_netdev_setup(struct net_device *net_dev)
+{
+ d_fnstart(3, NULL, "(net_dev %p)\n", net_dev);
+ ether_setup(net_dev);
+ net_dev->mtu = I2400M_MAX_MTU;
+ net_dev->tx_queue_len = I2400M_TX_QLEN;
+ net_dev->features =
+ NETIF_F_VLAN_CHALLENGED
+ | NETIF_F_HIGHDMA;
+ net_dev->flags =
+ IFF_NOARP /* i2400m is apure IP device */
+ & (~IFF_BROADCAST /* i2400m is P2P */
+ & ~IFF_MULTICAST);
+ net_dev->watchdog_timeo = I2400M_TX_TIMEOUT;
+ net_dev->open = i2400m_open;
+ net_dev->stop = i2400m_stop;
+ net_dev->hard_start_xmit = i2400m_hard_start_xmit;
+ net_dev->change_mtu = i2400m_change_mtu;
+ net_dev->tx_timeout = i2400m_tx_timeout;
+ d_fnend(3, NULL, "(net_dev %p) = void\n", net_dev);
+}
+EXPORT_SYMBOL_GPL(i2400m_netdev_setup);
+
diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c
new file mode 100644
index 000000000000..487ec58cea46
--- /dev/null
+++ b/drivers/net/wimax/i2400m/op-rfkill.c
@@ -0,0 +1,207 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Implement backend for the WiMAX stack rfkill support
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This 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.
+ *
+ *
+ * The WiMAX kernel stack integrates into RF-Kill and keeps the
+ * switches's status. We just need to:
+ *
+ * - report changes in the HW RF Kill switch [with
+ * wimax_rfkill_{sw,hw}_report(), which happens when we detect those
+ * indications coming through hardware reports]. We also do it on
+ * initialization to let the stack know the intial HW state.
+ *
+ * - implement indications from the stack to change the SW RF Kill
+ * switch (coming from sysfs, the wimax stack or user space).
+ */
+#include "i2400m.h"
+#include <linux/wimax/i2400m.h>
+
+
+
+#define D_SUBMODULE rfkill
+#include "debug-levels.h"
+
+/*
+ * Return true if the i2400m radio is in the requested wimax_rf_state state
+ *
+ */
+static
+int i2400m_radio_is(struct i2400m *i2400m, enum wimax_rf_state state)
+{
+ if (state == WIMAX_RF_OFF)
+ return i2400m->state == I2400M_SS_RF_OFF
+ || i2400m->state == I2400M_SS_RF_SHUTDOWN;
+ else if (state == WIMAX_RF_ON)
+ /* state == WIMAX_RF_ON */
+ return i2400m->state != I2400M_SS_RF_OFF
+ && i2400m->state != I2400M_SS_RF_SHUTDOWN;
+ else
+ BUG();
+}
+
+
+/*
+ * WiMAX stack operation: implement SW RFKill toggling
+ *
+ * @wimax_dev: device descriptor
+ * @skb: skb where the message has been received; skb->data is
+ * expected to point to the message payload.
+ * @genl_info: passed by the generic netlink layer
+ *
+ * Generic Netlink will call this function when a message is sent from
+ * userspace to change the software RF-Kill switch status.
+ *
+ * This function will set the device's sofware RF-Kill switch state to
+ * match what is requested.
+ *
+ * NOTE: the i2400m has a strict state machine; we can only set the
+ * RF-Kill switch when it is on, the HW RF-Kill is on and the
+ * device is initialized. So we ignore errors steaming from not
+ * being in the right state (-EILSEQ).
+ */
+int i2400m_op_rfkill_sw_toggle(struct wimax_dev *wimax_dev,
+ enum wimax_rf_state state)
+{
+ int result;
+ struct i2400m *i2400m = wimax_dev_to_i2400m(wimax_dev);
+ struct device *dev = i2400m_dev(i2400m);
+ struct sk_buff *ack_skb;
+ struct {
+ struct i2400m_l3l4_hdr hdr;
+ struct i2400m_tlv_rf_operation sw_rf;
+ } __attribute__((packed)) *cmd;
+ char strerr[32];
+
+ d_fnstart(4, dev, "(wimax_dev %p state %d)\n", wimax_dev, state);
+
+ result = -ENOMEM;
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ goto error_alloc;
+ cmd->hdr.type = cpu_to_le16(I2400M_MT_CMD_RF_CONTROL);
+ cmd->hdr.length = sizeof(cmd->sw_rf);
+ cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION);
+ cmd->sw_rf.hdr.type = cpu_to_le16(I2400M_TLV_RF_OPERATION);
+ cmd->sw_rf.hdr.length = cpu_to_le16(sizeof(cmd->sw_rf.status));
+ switch (state) {
+ case WIMAX_RF_OFF: /* RFKILL ON, radio OFF */
+ cmd->sw_rf.status = cpu_to_le32(2);
+ break;
+ case WIMAX_RF_ON: /* RFKILL OFF, radio ON */
+ cmd->sw_rf.status = cpu_to_le32(1);
+ break;
+ default:
+ BUG();
+ }
+
+ ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
+ result = PTR_ERR(ack_skb);
+ if (IS_ERR(ack_skb)) {
+ dev_err(dev, "Failed to issue 'RF Control' command: %d\n",
+ result);
+ goto error_msg_to_dev;
+ }
+ result = i2400m_msg_check_status(wimax_msg_data(ack_skb),
+ strerr, sizeof(strerr));
+ if (result < 0) {
+ dev_err(dev, "'RF Control' (0x%04x) command failed: %d - %s\n",
+ I2400M_MT_CMD_RF_CONTROL, result, strerr);
+ goto error_cmd;
+ }
+
+ /* Now we wait for the state to change to RADIO_OFF or RADIO_ON */
+ result = wait_event_timeout(
+ i2400m->state_wq, i2400m_radio_is(i2400m, state),
+ 5 * HZ);
+ if (result == 0)
+ result = -ETIMEDOUT;
+ if (result < 0)
+ dev_err(dev, "Error waiting for device to toggle RF state: "
+ "%d\n", result);
+ result = 0;
+error_cmd:
+ kfree_skb(ack_skb);
+error_msg_to_dev:
+error_alloc:
+ d_fnend(4, dev, "(wimax_dev %p state %d) = %d\n",
+ wimax_dev, state, result);
+ return result;
+}
+
+
+/*
+ * Inform the WiMAX stack of changes in the RF Kill switches reported
+ * by the device
+ *
+ * @i2400m: device descriptor
+ * @rfss: TLV for RF Switches status; already validated
+ *
+ * NOTE: the reports on RF switch status cannot be trusted
+ * or used until the device is in a state of RADIO_OFF
+ * or greater.
+ */
+void i2400m_report_tlv_rf_switches_status(
+ struct i2400m *i2400m,
+ const struct i2400m_tlv_rf_switches_status *rfss)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ enum i2400m_rf_switch_status hw, sw;
+ enum wimax_st wimax_state;
+
+ sw = le32_to_cpu(rfss->sw_rf_switch);
+ hw = le32_to_cpu(rfss->hw_rf_switch);
+
+ d_fnstart(3, dev, "(i2400m %p rfss %p [hw %u sw %u])\n",
+ i2400m, rfss, hw, sw);
+ /* We only process rw switch evens when the device has been
+ * fully initialized */
+ wimax_state = wimax_state_get(&i2400m->wimax_dev);
+ if (wimax_state < WIMAX_ST_RADIO_OFF) {
+ d_printf(3, dev, "ignoring RF switches report, state %u\n",
+ wimax_state);
+ goto out;
+ }
+ switch (sw) {
+ case I2400M_RF_SWITCH_ON: /* RF Kill disabled (radio on) */
+ wimax_report_rfkill_sw(&i2400m->wimax_dev, WIMAX_RF_ON);
+ break;
+ case I2400M_RF_SWITCH_OFF: /* RF Kill enabled (radio off) */
+ wimax_report_rfkill_sw(&i2400m->wimax_dev, WIMAX_RF_OFF);
+ break;
+ default:
+ dev_err(dev, "HW BUG? Unknown RF SW state 0x%x\n", sw);
+ }
+
+ switch (hw) {
+ case I2400M_RF_SWITCH_ON: /* RF Kill disabled (radio on) */
+ wimax_report_rfkill_hw(&i2400m->wimax_dev, WIMAX_RF_ON);
+ break;
+ case I2400M_RF_SWITCH_OFF: /* RF Kill enabled (radio off) */
+ wimax_report_rfkill_hw(&i2400m->wimax_dev, WIMAX_RF_OFF);
+ break;
+ default:
+ dev_err(dev, "HW BUG? Unknown RF HW state 0x%x\n", hw);
+ }
+out:
+ d_fnend(3, dev, "(i2400m %p rfss %p [hw %u sw %u]) = void\n",
+ i2400m, rfss, hw, sw);
+}
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
new file mode 100644
index 000000000000..6922022710ac
--- /dev/null
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -0,0 +1,534 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Handle incoming traffic and deliver it to the control or data planes
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ * - Initial implementation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * - Use skb_clone(), break up processing in chunks
+ * - Split transport/device specific
+ * - Make buffer size dynamic to exert less memory pressure
+ *
+ *
+ * This handles the RX path.
+ *
+ * We receive an RX message from the bus-specific driver, which
+ * contains one or more payloads that have potentially different
+ * destinataries (data or control paths).
+ *
+ * So we just take that payload from the transport specific code in
+ * the form of an skb, break it up in chunks (a cloned skb each in the
+ * case of network packets) and pass it to netdev or to the
+ * command/ack handler (and from there to the WiMAX stack).
+ *
+ * PROTOCOL FORMAT
+ *
+ * The format of the buffer is:
+ *
+ * HEADER (struct i2400m_msg_hdr)
+ * PAYLOAD DESCRIPTOR 0 (struct i2400m_pld)
+ * PAYLOAD DESCRIPTOR 1
+ * ...
+ * PAYLOAD DESCRIPTOR N
+ * PAYLOAD 0 (raw bytes)
+ * PAYLOAD 1
+ * ...
+ * PAYLOAD N
+ *
+ * See tx.c for a deeper description on alignment requirements and
+ * other fun facts of it.
+ *
+ * ROADMAP
+ *
+ * i2400m_rx
+ * i2400m_rx_msg_hdr_check
+ * i2400m_rx_pl_descr_check
+ * i2400m_rx_payload
+ * i2400m_net_rx
+ * i2400m_rx_ctl
+ * i2400m_msg_size_check
+ * i2400m_report_hook_work [in a workqueue]
+ * i2400m_report_hook
+ * wimax_msg_to_user
+ * i2400m_rx_ctl_ack
+ * wimax_msg_to_user_alloc
+ * i2400m_rx_trace
+ * i2400m_msg_size_check
+ * wimax_msg
+ */
+#include <linux/kernel.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+#include "i2400m.h"
+
+
+#define D_SUBMODULE rx
+#include "debug-levels.h"
+
+struct i2400m_report_hook_args {
+ struct sk_buff *skb_rx;
+ const struct i2400m_l3l4_hdr *l3l4_hdr;
+ size_t size;
+};
+
+
+/*
+ * Execute i2400m_report_hook in a workqueue
+ *
+ * Unpacks arguments from the deferred call, executes it and then
+ * drops the references.
+ *
+ * Obvious NOTE: References are needed because we are a separate
+ * thread; otherwise the buffer changes under us because it is
+ * released by the original caller.
+ */
+static
+void i2400m_report_hook_work(struct work_struct *ws)
+{
+ struct i2400m_work *iw =
+ container_of(ws, struct i2400m_work, ws);
+ struct i2400m_report_hook_args *args = (void *) iw->pl;
+ i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size);
+ kfree_skb(args->skb_rx);
+ i2400m_put(iw->i2400m);
+ kfree(iw);
+}
+
+
+/*
+ * Process an ack to a command
+ *
+ * @i2400m: device descriptor
+ * @payload: pointer to message
+ * @size: size of the message
+ *
+ * Pass the acknodledgment (in an skb) to the thread that is waiting
+ * for it in i2400m->msg_completion.
+ *
+ * We need to coordinate properly with the thread waiting for the
+ * ack. Check if it is waiting or if it is gone. We loose the spinlock
+ * to avoid allocating on atomic contexts (yeah, could use GFP_ATOMIC,
+ * but this is not so speed critical).
+ */
+static
+void i2400m_rx_ctl_ack(struct i2400m *i2400m,
+ const void *payload, size_t size)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
+ unsigned long flags;
+ struct sk_buff *ack_skb;
+
+ /* Anyone waiting for an answer? */
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ if (i2400m->ack_skb != ERR_PTR(-EINPROGRESS)) {
+ dev_err(dev, "Huh? reply to command with no waiters\n");
+ goto error_no_waiter;
+ }
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+
+ ack_skb = wimax_msg_alloc(wimax_dev, NULL, payload, size, GFP_KERNEL);
+
+ /* Check waiter didn't time out waiting for the answer... */
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ if (i2400m->ack_skb != ERR_PTR(-EINPROGRESS)) {
+ d_printf(1, dev, "Huh? waiter for command reply cancelled\n");
+ goto error_waiter_cancelled;
+ }
+ if (ack_skb == NULL) {
+ dev_err(dev, "CMD/GET/SET ack: cannot allocate SKB\n");
+ i2400m->ack_skb = ERR_PTR(-ENOMEM);
+ } else
+ i2400m->ack_skb = ack_skb;
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+ complete(&i2400m->msg_completion);
+ return;
+
+error_waiter_cancelled:
+ if (ack_skb)
+ kfree_skb(ack_skb);
+error_no_waiter:
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+ return;
+}
+
+
+/*
+ * Receive and process a control payload
+ *
+ * @i2400m: device descriptor
+ * @skb_rx: skb that contains the payload (for reference counting)
+ * @payload: pointer to message
+ * @size: size of the message
+ *
+ * There are two types of control RX messages: reports (asynchronous,
+ * like your every day interrupts) and 'acks' (reponses to a command,
+ * get or set request).
+ *
+ * If it is a report, we run hooks on it (to extract information for
+ * things we need to do in the driver) and then pass it over to the
+ * WiMAX stack to send it to user space.
+ *
+ * NOTE: report processing is done in a workqueue specific to the
+ * generic driver, to avoid deadlocks in the system.
+ *
+ * If it is not a report, it is an ack to a previously executed
+ * command, set or get, so wake up whoever is waiting for it from
+ * i2400m_msg_to_dev(). i2400m_rx_ctl_ack() takes care of that.
+ *
+ * Note that the sizes we pass to other functions from here are the
+ * sizes of the _l3l4_hdr + payload, not full buffer sizes, as we have
+ * verified in _msg_size_check() that they are congruent.
+ *
+ * For reports: We can't clone the original skb where the data is
+ * because we need to send this up via netlink; netlink has to add
+ * headers and we can't overwrite what's preceeding the payload...as
+ * it is another message. So we just dup them.
+ */
+static
+void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx,
+ const void *payload, size_t size)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ const struct i2400m_l3l4_hdr *l3l4_hdr = payload;
+ unsigned msg_type;
+
+ result = i2400m_msg_size_check(i2400m, l3l4_hdr, size);
+ if (result < 0) {
+ dev_err(dev, "HW BUG? device sent a bad message: %d\n",
+ result);
+ goto error_check;
+ }
+ msg_type = le16_to_cpu(l3l4_hdr->type);
+ d_printf(1, dev, "%s 0x%04x: %zu bytes\n",
+ msg_type & I2400M_MT_REPORT_MASK ? "REPORT" : "CMD/SET/GET",
+ msg_type, size);
+ d_dump(2, dev, l3l4_hdr, size);
+ if (msg_type & I2400M_MT_REPORT_MASK) {
+ /* These hooks have to be ran serialized; as well, the
+ * handling might force the execution of commands, and
+ * that might cause reentrancy issues with
+ * bus-specific subdrivers and workqueues. So we run
+ * it in a separate workqueue. */
+ struct i2400m_report_hook_args args = {
+ .skb_rx = skb_rx,
+ .l3l4_hdr = l3l4_hdr,
+ .size = size
+ };
+ if (unlikely(i2400m->ready == 0)) /* only send if up */
+ return;
+ skb_get(skb_rx);
+ i2400m_queue_work(i2400m, i2400m_report_hook_work,
+ GFP_KERNEL, &args, sizeof(args));
+ result = wimax_msg(&i2400m->wimax_dev, NULL, l3l4_hdr, size,
+ GFP_KERNEL);
+ if (result < 0)
+ dev_err(dev, "error sending report to userspace: %d\n",
+ result);
+ } else /* an ack to a CMD, GET or SET */
+ i2400m_rx_ctl_ack(i2400m, payload, size);
+error_check:
+ return;
+}
+
+
+
+
+/*
+ * Receive and send up a trace
+ *
+ * @i2400m: device descriptor
+ * @skb_rx: skb that contains the trace (for reference counting)
+ * @payload: pointer to trace message inside the skb
+ * @size: size of the message
+ *
+ * THe i2400m might produce trace information (diagnostics) and we
+ * send them through a different kernel-to-user pipe (to avoid
+ * clogging it).
+ *
+ * As in i2400m_rx_ctl(), we can't clone the original skb where the
+ * data is because we need to send this up via netlink; netlink has to
+ * add headers and we can't overwrite what's preceeding the
+ * payload...as it is another message. So we just dup them.
+ */
+static
+void i2400m_rx_trace(struct i2400m *i2400m,
+ const void *payload, size_t size)
+{
+ int result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
+ const struct i2400m_l3l4_hdr *l3l4_hdr = payload;
+ unsigned msg_type;
+
+ result = i2400m_msg_size_check(i2400m, l3l4_hdr, size);
+ if (result < 0) {
+ dev_err(dev, "HW BUG? device sent a bad trace message: %d\n",
+ result);
+ goto error_check;
+ }
+ msg_type = le16_to_cpu(l3l4_hdr->type);
+ d_printf(1, dev, "Trace %s 0x%04x: %zu bytes\n",
+ msg_type & I2400M_MT_REPORT_MASK ? "REPORT" : "CMD/SET/GET",
+ msg_type, size);
+ d_dump(2, dev, l3l4_hdr, size);
+ if (unlikely(i2400m->ready == 0)) /* only send if up */
+ return;
+ result = wimax_msg(wimax_dev, "trace", l3l4_hdr, size, GFP_KERNEL);
+ if (result < 0)
+ dev_err(dev, "error sending trace to userspace: %d\n",
+ result);
+error_check:
+ return;
+}
+
+
+/*
+ * Act on a received payload
+ *
+ * @i2400m: device instance
+ * @skb_rx: skb where the transaction was received
+ * @single: 1 if there is only one payload, 0 otherwise
+ * @pld: payload descriptor
+ * @payload: payload data
+ *
+ * Upon reception of a payload, look at its guts in the payload
+ * descriptor and decide what to do with it.
+ */
+static
+void i2400m_rx_payload(struct i2400m *i2400m, struct sk_buff *skb_rx,
+ unsigned single, const struct i2400m_pld *pld,
+ const void *payload)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ size_t pl_size = i2400m_pld_size(pld);
+ enum i2400m_pt pl_type = i2400m_pld_type(pld);
+
+ switch (pl_type) {
+ case I2400M_PT_DATA:
+ d_printf(3, dev, "RX: data payload %zu bytes\n", pl_size);
+ i2400m_net_rx(i2400m, skb_rx, single, payload, pl_size);
+ break;
+ case I2400M_PT_CTRL:
+ i2400m_rx_ctl(i2400m, skb_rx, payload, pl_size);
+ break;
+ case I2400M_PT_TRACE:
+ i2400m_rx_trace(i2400m, payload, pl_size);
+ break;
+ default: /* Anything else shouldn't come to the host */
+ if (printk_ratelimit())
+ dev_err(dev, "RX: HW BUG? unexpected payload type %u\n",
+ pl_type);
+ }
+}
+
+
+/*
+ * Check a received transaction's message header
+ *
+ * @i2400m: device descriptor
+ * @msg_hdr: message header
+ * @buf_size: size of the received buffer
+ *
+ * Check that the declarations done by a RX buffer message header are
+ * sane and consistent with the amount of data that was received.
+ */
+static
+int i2400m_rx_msg_hdr_check(struct i2400m *i2400m,
+ const struct i2400m_msg_hdr *msg_hdr,
+ size_t buf_size)
+{
+ int result = -EIO;
+ struct device *dev = i2400m_dev(i2400m);
+ if (buf_size < sizeof(*msg_hdr)) {
+ dev_err(dev, "RX: HW BUG? message with short header (%zu "
+ "vs %zu bytes expected)\n", buf_size, sizeof(*msg_hdr));
+ goto error;
+ }
+ if (msg_hdr->barker != cpu_to_le32(I2400M_D2H_MSG_BARKER)) {
+ dev_err(dev, "RX: HW BUG? message received with unknown "
+ "barker 0x%08x (buf_size %zu bytes)\n",
+ le32_to_cpu(msg_hdr->barker), buf_size);
+ goto error;
+ }
+ if (msg_hdr->num_pls == 0) {
+ dev_err(dev, "RX: HW BUG? zero payload packets in message\n");
+ goto error;
+ }
+ if (le16_to_cpu(msg_hdr->num_pls) > I2400M_MAX_PLS_IN_MSG) {
+ dev_err(dev, "RX: HW BUG? message contains more payload "
+ "than maximum; ignoring.\n");
+ goto error;
+ }
+ result = 0;
+error:
+ return result;
+}
+
+
+/*
+ * Check a payload descriptor against the received data
+ *
+ * @i2400m: device descriptor
+ * @pld: payload descriptor
+ * @pl_itr: offset (in bytes) in the received buffer the payload is
+ * located
+ * @buf_size: size of the received buffer
+ *
+ * Given a payload descriptor (part of a RX buffer), check it is sane
+ * and that the data it declares fits in the buffer.
+ */
+static
+int i2400m_rx_pl_descr_check(struct i2400m *i2400m,
+ const struct i2400m_pld *pld,
+ size_t pl_itr, size_t buf_size)
+{
+ int result = -EIO;
+ struct device *dev = i2400m_dev(i2400m);
+ size_t pl_size = i2400m_pld_size(pld);
+ enum i2400m_pt pl_type = i2400m_pld_type(pld);
+
+ if (pl_size > i2400m->bus_pl_size_max) {
+ dev_err(dev, "RX: HW BUG? payload @%zu: size %zu is "
+ "bigger than maximum %zu; ignoring message\n",
+ pl_itr, pl_size, i2400m->bus_pl_size_max);
+ goto error;
+ }
+ if (pl_itr + pl_size > buf_size) { /* enough? */
+ dev_err(dev, "RX: HW BUG? payload @%zu: size %zu "
+ "goes beyond the received buffer "
+ "size (%zu bytes); ignoring message\n",
+ pl_itr, pl_size, buf_size);
+ goto error;
+ }
+ if (pl_type >= I2400M_PT_ILLEGAL) {
+ dev_err(dev, "RX: HW BUG? illegal payload type %u; "
+ "ignoring message\n", pl_type);
+ goto error;
+ }
+ result = 0;
+error:
+ return result;
+}
+
+
+/**
+ * i2400m_rx - Receive a buffer of data from the device
+ *
+ * @i2400m: device descriptor
+ * @skb: skbuff where the data has been received
+ *
+ * Parse in a buffer of data that contains an RX message sent from the
+ * device. See the file header for the format. Run all checks on the
+ * buffer header, then run over each payload's descriptors, verify
+ * their consistency and act on each payload's contents. If
+ * everything is succesful, update the device's statistics.
+ *
+ * Note: You need to set the skb to contain only the length of the
+ * received buffer; for that, use skb_trim(skb, RECEIVED_SIZE).
+ *
+ * Returns:
+ *
+ * 0 if ok, < 0 errno on error
+ *
+ * If ok, this function owns now the skb and the caller DOESN'T have
+ * to run kfree_skb() on it. However, on error, the caller still owns
+ * the skb and it is responsible for releasing it.
+ */
+int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb)
+{
+ int i, result;
+ struct device *dev = i2400m_dev(i2400m);
+ const struct i2400m_msg_hdr *msg_hdr;
+ size_t pl_itr, pl_size, skb_len;
+ unsigned long flags;
+ unsigned num_pls;
+
+ skb_len = skb->len;
+ d_fnstart(4, dev, "(i2400m %p skb %p [size %zu])\n",
+ i2400m, skb, skb_len);
+ result = -EIO;
+ msg_hdr = (void *) skb->data;
+ result = i2400m_rx_msg_hdr_check(i2400m, msg_hdr, skb->len);
+ if (result < 0)
+ goto error_msg_hdr_check;
+ result = -EIO;
+ num_pls = le16_to_cpu(msg_hdr->num_pls);
+ pl_itr = sizeof(*msg_hdr) + /* Check payload descriptor(s) */
+ num_pls * sizeof(msg_hdr->pld[0]);
+ pl_itr = ALIGN(pl_itr, I2400M_PL_PAD);
+ if (pl_itr > skb->len) { /* got all the payload descriptors? */
+ dev_err(dev, "RX: HW BUG? message too short (%u bytes) for "
+ "%u payload descriptors (%zu each, total %zu)\n",
+ skb->len, num_pls, sizeof(msg_hdr->pld[0]), pl_itr);
+ goto error_pl_descr_short;
+ }
+ /* Walk each payload payload--check we really got it */
+ for (i = 0; i < num_pls; i++) {
+ /* work around old gcc warnings */
+ pl_size = i2400m_pld_size(&msg_hdr->pld[i]);
+ result = i2400m_rx_pl_descr_check(i2400m, &msg_hdr->pld[i],
+ pl_itr, skb->len);
+ if (result < 0)
+ goto error_pl_descr_check;
+ i2400m_rx_payload(i2400m, skb, num_pls == 1, &msg_hdr->pld[i],
+ skb->data + pl_itr);
+ pl_itr += ALIGN(pl_size, I2400M_PL_PAD);
+ cond_resched(); /* Don't monopolize */
+ }
+ kfree_skb(skb);
+ /* Update device statistics */
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ i2400m->rx_pl_num += i;
+ if (i > i2400m->rx_pl_max)
+ i2400m->rx_pl_max = i;
+ if (i < i2400m->rx_pl_min)
+ i2400m->rx_pl_min = i;
+ i2400m->rx_num++;
+ i2400m->rx_size_acc += skb->len;
+ if (skb->len < i2400m->rx_size_min)
+ i2400m->rx_size_min = skb->len;
+ if (skb->len > i2400m->rx_size_max)
+ i2400m->rx_size_max = skb->len;
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+error_pl_descr_check:
+error_pl_descr_short:
+error_msg_hdr_check:
+ d_fnend(4, dev, "(i2400m %p skb %p [size %zu]) = %d\n",
+ i2400m, skb, skb_len, result);
+ return result;
+}
+EXPORT_SYMBOL_GPL(i2400m_rx);
diff --git a/drivers/net/wimax/i2400m/sdio-debug-levels.h b/drivers/net/wimax/i2400m/sdio-debug-levels.h
new file mode 100644
index 000000000000..c51998741301
--- /dev/null
+++ b/drivers/net/wimax/i2400m/sdio-debug-levels.h
@@ -0,0 +1,22 @@
+/*
+ * debug levels control file for the i2400m module's
+ */
+#ifndef __debug_levels__h__
+#define __debug_levels__h__
+
+/* Maximum compile and run time debug level for all submodules */
+#define D_MODULENAME i2400m_sdio
+#define D_MASTER CONFIG_WIMAX_I2400M_DEBUG_LEVEL
+
+#include <linux/wimax/debug.h>
+
+/* List of all the enabled modules */
+enum d_module {
+ D_SUBMODULE_DECLARE(main),
+ D_SUBMODULE_DECLARE(tx),
+ D_SUBMODULE_DECLARE(rx),
+ D_SUBMODULE_DECLARE(fw)
+};
+
+
+#endif /* #ifndef __debug_levels__h__ */
diff --git a/drivers/net/wimax/i2400m/sdio-fw.c b/drivers/net/wimax/i2400m/sdio-fw.c
new file mode 100644
index 000000000000..3487205d8f50
--- /dev/null
+++ b/drivers/net/wimax/i2400m/sdio-fw.c
@@ -0,0 +1,224 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Firmware uploader's SDIO specifics
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * - Initial implementation
+ *
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * - Bus generic/specific split for USB
+ *
+ * Dirk Brandewie <dirk.j.brandewie@intel.com>
+ * - Initial implementation for SDIO
+ *
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * - SDIO rehash for changes in the bus-driver model
+ *
+ * THE PROCEDURE
+ *
+ * See fw.c for the generic description of this procedure.
+ *
+ * This file implements only the SDIO specifics. It boils down to how
+ * to send a command and waiting for an acknowledgement from the
+ * device. We do polled reads.
+ *
+ * COMMAND EXECUTION
+ *
+ * THe generic firmware upload code will call i2400m_bus_bm_cmd_send()
+ * to send commands.
+ *
+ * The SDIO devices expects things in 256 byte blocks, so it will pad
+ * it, compute the checksum (if needed) and pass it to SDIO.
+ *
+ * ACK RECEPTION
+ *
+ * This works in polling mode -- the fw loader says when to wait for
+ * data and for that it calls i2400ms_bus_bm_wait_for_ack().
+ *
+ * This will poll the device for data until it is received. We need to
+ * receive at least as much bytes as where asked for (although it'll
+ * always be a multiple of 256 bytes).
+ */
+#include <linux/mmc/sdio_func.h>
+#include "i2400m-sdio.h"
+
+
+#define D_SUBMODULE fw
+#include "sdio-debug-levels.h"
+
+/*
+ * Send a boot-mode command to the SDIO function
+ *
+ * We use a bounce buffer (i2400m->bm_cmd_buf) because we need to
+ * touch the header if the RAW flag is not set.
+ *
+ * @flags: pass thru from i2400m_bm_cmd()
+ * @return: cmd_size if ok, < 0 errno code on error.
+ *
+ * Note the command is padded to the SDIO block size for the device.
+ */
+ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *i2400m,
+ const struct i2400m_bootrom_header *_cmd,
+ size_t cmd_size, int flags)
+{
+ ssize_t result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
+ int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd);
+ struct i2400m_bootrom_header *cmd;
+ /* SDIO restriction */
+ size_t cmd_size_a = ALIGN(cmd_size, I2400MS_BLK_SIZE);
+
+ d_fnstart(5, dev, "(i2400m %p cmd %p size %zu)\n",
+ i2400m, _cmd, cmd_size);
+ result = -E2BIG;
+ if (cmd_size > I2400M_BM_CMD_BUF_SIZE)
+ goto error_too_big;
+
+ memcpy(i2400m->bm_cmd_buf, _cmd, cmd_size); /* Prep command */
+ cmd = i2400m->bm_cmd_buf;
+ if (cmd_size_a > cmd_size) /* Zero pad space */
+ memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size);
+ if ((flags & I2400M_BM_CMD_RAW) == 0) {
+ if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0))
+ dev_warn(dev, "SW BUG: response_required == 0\n");
+ i2400m_bm_cmd_prepare(cmd);
+ }
+ d_printf(4, dev, "BM cmd %d: %zu bytes (%zu padded)\n",
+ opcode, cmd_size, cmd_size_a);
+ d_dump(5, dev, cmd, cmd_size);
+
+ sdio_claim_host(i2400ms->func); /* Send & check */
+ result = sdio_memcpy_toio(i2400ms->func, I2400MS_DATA_ADDR,
+ i2400m->bm_cmd_buf, cmd_size_a);
+ sdio_release_host(i2400ms->func);
+ if (result < 0) {
+ dev_err(dev, "BM cmd %d: cannot send: %ld\n",
+ opcode, (long) result);
+ goto error_cmd_send;
+ }
+ result = cmd_size;
+error_cmd_send:
+error_too_big:
+ d_fnend(5, dev, "(i2400m %p cmd %p size %zu) = %d\n",
+ i2400m, _cmd, cmd_size, (int) result);
+ return result;
+}
+
+
+/*
+ * Read an ack from the device's boot-mode (polling)
+ *
+ * @i2400m:
+ * @_ack: pointer to where to store the read data
+ * @ack_size: how many bytes we should read
+ *
+ * Returns: < 0 errno code on error; otherwise, amount of received bytes.
+ *
+ * The ACK for a BM command is always at least sizeof(*ack) bytes, so
+ * check for that. We don't need to check for device reboots
+ *
+ * NOTE: We do an artificial timeout of 1 sec over the SDIO timeout;
+ * this way we have control over it...there is no way that I know
+ * of setting an SDIO transaction timeout.
+ */
+ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m,
+ struct i2400m_bootrom_header *ack,
+ size_t ack_size)
+{
+ int result;
+ ssize_t rx_size;
+ u64 timeout;
+ struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
+ struct sdio_func *func = i2400ms->func;
+ struct device *dev = &func->dev;
+
+ BUG_ON(sizeof(*ack) > ack_size);
+
+ d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n",
+ i2400m, ack, ack_size);
+
+ timeout = get_jiffies_64() + 2 * HZ;
+ sdio_claim_host(func);
+ while (1) {
+ if (time_after64(get_jiffies_64(), timeout)) {
+ rx_size = -ETIMEDOUT;
+ dev_err(dev, "timeout waiting for ack data\n");
+ goto error_timedout;
+ }
+
+ /* Find the RX size, check if it fits or not -- it if
+ * doesn't fit, fail, as we have no way to dispose of
+ * the extra data. */
+ rx_size = __i2400ms_rx_get_size(i2400ms);
+ if (rx_size < 0)
+ goto error_rx_get_size;
+ result = -ENOSPC; /* Check it fits */
+ if (rx_size < sizeof(*ack)) {
+ rx_size = -EIO;
+ dev_err(dev, "HW BUG? received is too small (%zu vs "
+ "%zu needed)\n", sizeof(*ack), rx_size);
+ goto error_too_small;
+ }
+ if (rx_size > I2400M_BM_ACK_BUF_SIZE) {
+ dev_err(dev, "SW BUG? BM_ACK_BUF is too small (%u vs "
+ "%zu needed)\n", I2400M_BM_ACK_BUF_SIZE,
+ rx_size);
+ goto error_too_small;
+ }
+
+ /* Read it */
+ result = sdio_memcpy_fromio(func, i2400m->bm_ack_buf,
+ I2400MS_DATA_ADDR, rx_size);
+ if (result == -ETIMEDOUT || result == -ETIME)
+ continue;
+ if (result < 0) {
+ dev_err(dev, "BM SDIO receive (%zu B) failed: %d\n",
+ rx_size, result);
+ goto error_read;
+ } else
+ break;
+ }
+ rx_size = min((ssize_t)ack_size, rx_size);
+ memcpy(ack, i2400m->bm_ack_buf, rx_size);
+error_read:
+error_too_small:
+error_rx_get_size:
+error_timedout:
+ sdio_release_host(func);
+ d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %ld\n",
+ i2400m, ack, ack_size, (long) rx_size);
+ return rx_size;
+}
diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c
new file mode 100644
index 000000000000..a3008b904f7d
--- /dev/null
+++ b/drivers/net/wimax/i2400m/sdio-rx.c
@@ -0,0 +1,255 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * SDIO RX handling
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Dirk Brandewie <dirk.j.brandewie@intel.com>
+ * - Initial implementation
+ *
+ *
+ * This handles the RX path on SDIO.
+ *
+ * The SDIO bus driver calls the "irq" routine when data is available.
+ * This is not a traditional interrupt routine since the SDIO bus
+ * driver calls us from its irq thread context. Because of this
+ * sleeping in the SDIO RX IRQ routine is okay.
+ *
+ * From there on, we obtain the size of the data that is available,
+ * allocate an skb, copy it and then pass it to the generic driver's
+ * RX routine [i2400m_rx()].
+ *
+ * ROADMAP
+ *
+ * i2400ms_irq()
+ * i2400ms_rx()
+ * __i2400ms_rx_get_size()
+ * i2400m_rx()
+ *
+ * i2400ms_rx_setup()
+ *
+ * i2400ms_rx_release()
+ */
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/skbuff.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+#include "i2400m-sdio.h"
+
+#define D_SUBMODULE rx
+#include "sdio-debug-levels.h"
+
+
+/*
+ * Read and return the amount of bytes available for RX
+ *
+ * The RX size has to be read like this: byte reads of three
+ * sequential locations; then glue'em together.
+ *
+ * sdio_readl() doesn't work.
+ */
+ssize_t __i2400ms_rx_get_size(struct i2400ms *i2400ms)
+{
+ int ret, cnt, val;
+ ssize_t rx_size;
+ unsigned xfer_size_addr;
+ struct sdio_func *func = i2400ms->func;
+ struct device *dev = &i2400ms->func->dev;
+
+ d_fnstart(7, dev, "(i2400ms %p)\n", i2400ms);
+ xfer_size_addr = I2400MS_INTR_GET_SIZE_ADDR;
+ rx_size = 0;
+ for (cnt = 0; cnt < 3; cnt++) {
+ val = sdio_readb(func, xfer_size_addr + cnt, &ret);
+ if (ret < 0) {
+ dev_err(dev, "RX: Can't read byte %d of RX size from "
+ "0x%08x: %d\n", cnt, xfer_size_addr + cnt, ret);
+ rx_size = ret;
+ goto error_read;
+ }
+ rx_size = rx_size << 8 | (val & 0xff);
+ }
+ d_printf(6, dev, "RX: rx_size is %ld\n", (long) rx_size);
+error_read:
+ d_fnend(7, dev, "(i2400ms %p) = %ld\n", i2400ms, (long) rx_size);
+ return rx_size;
+}
+
+
+/*
+ * Read data from the device (when in normal)
+ *
+ * Allocate an SKB of the right size, read the data in and then
+ * deliver it to the generic layer.
+ *
+ * We also check for a reboot barker. That means the device died and
+ * we have to reboot it.
+ */
+static
+void i2400ms_rx(struct i2400ms *i2400ms)
+{
+ int ret;
+ struct sdio_func *func = i2400ms->func;
+ struct device *dev = &func->dev;
+ struct i2400m *i2400m = &i2400ms->i2400m;
+ struct sk_buff *skb;
+ ssize_t rx_size;
+
+ d_fnstart(7, dev, "(i2400ms %p)\n", i2400ms);
+ rx_size = __i2400ms_rx_get_size(i2400ms);
+ if (rx_size < 0) {
+ ret = rx_size;
+ goto error_get_size;
+ }
+ ret = -ENOMEM;
+ skb = alloc_skb(rx_size, GFP_ATOMIC);
+ if (NULL == skb) {
+ dev_err(dev, "RX: unable to alloc skb\n");
+ goto error_alloc_skb;
+ }
+
+ ret = sdio_memcpy_fromio(func, skb->data,
+ I2400MS_DATA_ADDR, rx_size);
+ if (ret < 0) {
+ dev_err(dev, "RX: SDIO data read failed: %d\n", ret);
+ goto error_memcpy_fromio;
+ }
+ /* Check if device has reset */
+ if (!memcmp(skb->data, i2400m_NBOOT_BARKER,
+ sizeof(i2400m_NBOOT_BARKER))
+ || !memcmp(skb->data, i2400m_SBOOT_BARKER,
+ sizeof(i2400m_SBOOT_BARKER))) {
+ ret = i2400m_dev_reset_handle(i2400m);
+ kfree_skb(skb);
+ } else {
+ skb_put(skb, rx_size);
+ i2400m_rx(i2400m, skb);
+ }
+ d_fnend(7, dev, "(i2400ms %p) = void\n", i2400ms);
+ return;
+
+error_memcpy_fromio:
+ kfree_skb(skb);
+error_alloc_skb:
+error_get_size:
+ d_fnend(7, dev, "(i2400ms %p) = %d\n", i2400ms, ret);
+ return;
+}
+
+
+/*
+ * Process an interrupt from the SDIO card
+ *
+ * FIXME: need to process other events that are not just ready-to-read
+ *
+ * Checks there is data ready and then proceeds to read it.
+ */
+static
+void i2400ms_irq(struct sdio_func *func)
+{
+ int ret;
+ struct i2400ms *i2400ms = sdio_get_drvdata(func);
+ struct i2400m *i2400m = &i2400ms->i2400m;
+ struct device *dev = &func->dev;
+ int val;
+
+ d_fnstart(6, dev, "(i2400ms %p)\n", i2400ms);
+ val = sdio_readb(func, I2400MS_INTR_STATUS_ADDR, &ret);
+ if (ret < 0) {
+ dev_err(dev, "RX: Can't read interrupt status: %d\n", ret);
+ goto error_no_irq;
+ }
+ if (!val) {
+ dev_err(dev, "RX: BUG? got IRQ but no interrupt ready?\n");
+ goto error_no_irq;
+ }
+ sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret);
+ if (WARN_ON(i2400m->boot_mode != 0))
+ dev_err(dev, "RX: SW BUG? boot mode and IRQ is up?\n");
+ else
+ i2400ms_rx(i2400ms);
+error_no_irq:
+ d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms);
+ return;
+}
+
+
+/*
+ * Setup SDIO RX
+ *
+ * Hooks up the IRQ handler and then enables IRQs.
+ */
+int i2400ms_rx_setup(struct i2400ms *i2400ms)
+{
+ int result;
+ struct sdio_func *func = i2400ms->func;
+ struct device *dev = &func->dev;
+
+ d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
+ sdio_claim_host(func);
+ result = sdio_claim_irq(func, i2400ms_irq);
+ if (result < 0) {
+ dev_err(dev, "Cannot claim IRQ: %d\n", result);
+ goto error_irq_claim;
+ }
+ result = 0;
+ sdio_writeb(func, 1, I2400MS_INTR_ENABLE_ADDR, &result);
+ if (result < 0) {
+ sdio_release_irq(func);
+ dev_err(dev, "Failed to enable interrupts %d\n", result);
+ }
+error_irq_claim:
+ sdio_release_host(func);
+ d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result);
+ return result;
+}
+
+
+/*
+ * Tear down SDIO RX
+ *
+ * Disables IRQs in the device and removes the IRQ handler.
+ */
+void i2400ms_rx_release(struct i2400ms *i2400ms)
+{
+ int result;
+ struct sdio_func *func = i2400ms->func;
+ struct device *dev = &func->dev;
+
+ d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
+ sdio_claim_host(func);
+ sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result);
+ sdio_release_irq(func);
+ sdio_release_host(func);
+ d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result);
+}
diff --git a/drivers/net/wimax/i2400m/sdio-tx.c b/drivers/net/wimax/i2400m/sdio-tx.c
new file mode 100644
index 000000000000..5105a5ebc44f
--- /dev/null
+++ b/drivers/net/wimax/i2400m/sdio-tx.c
@@ -0,0 +1,153 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * SDIO TX transaction backends
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Dirk Brandewie <dirk.j.brandewie@intel.com>
+ * - Initial implementation
+ *
+ *
+ * Takes the TX messages in the i2400m's driver TX FIFO and sends them
+ * to the device until there are no more.
+ *
+ * If we fail sending the message, we just drop it. There isn't much
+ * we can do at this point. Most of the traffic is network, which has
+ * recovery methods for dropped packets.
+ *
+ * The SDIO functions are not atomic, so we can't run from the context
+ * where i2400m->bus_tx_kick() [i2400ms_bus_tx_kick()] is being called
+ * (some times atomic). Thus, the actual TX work is deferred to a
+ * workqueue.
+ *
+ * ROADMAP
+ *
+ * i2400ms_bus_tx_kick()
+ * i2400ms_tx_submit() [through workqueue]
+ *
+ * i2400m_tx_setup()
+ *
+ * i2400m_tx_release()
+ */
+#include <linux/mmc/sdio_func.h>
+#include "i2400m-sdio.h"
+
+#define D_SUBMODULE tx
+#include "sdio-debug-levels.h"
+
+
+/*
+ * Pull TX transations from the TX FIFO and send them to the device
+ * until there are no more.
+ */
+static
+void i2400ms_tx_submit(struct work_struct *ws)
+{
+ int result;
+ struct i2400ms *i2400ms = container_of(ws, struct i2400ms, tx_worker);
+ struct i2400m *i2400m = &i2400ms->i2400m;
+ struct sdio_func *func = i2400ms->func;
+ struct device *dev = &func->dev;
+ struct i2400m_msg_hdr *tx_msg;
+ size_t tx_msg_size;
+
+ d_fnstart(4, dev, "(i2400ms %p, i2400m %p)\n", i2400ms, i2400ms);
+
+ while (NULL != (tx_msg = i2400m_tx_msg_get(i2400m, &tx_msg_size))) {
+ d_printf(2, dev, "TX: submitting %zu bytes\n", tx_msg_size);
+ d_dump(5, dev, tx_msg, tx_msg_size);
+
+ sdio_claim_host(func);
+ result = sdio_memcpy_toio(func, 0, tx_msg, tx_msg_size);
+ sdio_release_host(func);
+
+ i2400m_tx_msg_sent(i2400m);
+
+ if (result < 0) {
+ dev_err(dev, "TX: cannot submit TX; tx_msg @%zu %zu B:"
+ " %d\n", (void *) tx_msg - i2400m->tx_buf,
+ tx_msg_size, result);
+ }
+
+ d_printf(2, dev, "TX: %zub submitted\n", tx_msg_size);
+ }
+
+ d_fnend(4, dev, "(i2400ms %p) = void\n", i2400ms);
+}
+
+
+/*
+ * The generic driver notifies us that there is data ready for TX
+ *
+ * Schedule a run of i2400ms_tx_submit() to handle it.
+ */
+void i2400ms_bus_tx_kick(struct i2400m *i2400m)
+{
+ struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
+ struct device *dev = &i2400ms->func->dev;
+
+ d_fnstart(3, dev, "(i2400m %p) = void\n", i2400m);
+
+ /* schedule tx work, this is because tx may block, therefore
+ * it has to run in a thread context.
+ */
+ queue_work(i2400ms->tx_workqueue, &i2400ms->tx_worker);
+
+ d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
+}
+
+int i2400ms_tx_setup(struct i2400ms *i2400ms)
+{
+ int result;
+ struct device *dev = &i2400ms->func->dev;
+ struct i2400m *i2400m = &i2400ms->i2400m;
+
+ d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
+
+ INIT_WORK(&i2400ms->tx_worker, i2400ms_tx_submit);
+ snprintf(i2400ms->tx_wq_name, sizeof(i2400ms->tx_wq_name),
+ "%s-tx", i2400m->wimax_dev.name);
+ i2400ms->tx_workqueue =
+ create_singlethread_workqueue(i2400ms->tx_wq_name);
+ if (NULL == i2400ms->tx_workqueue) {
+ dev_err(dev, "TX: failed to create workqueue\n");
+ result = -ENOMEM;
+ } else
+ result = 0;
+ d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result);
+ return result;
+}
+
+void i2400ms_tx_release(struct i2400ms *i2400ms)
+{
+ destroy_workqueue(i2400ms->tx_workqueue);
+}
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
new file mode 100644
index 000000000000..1bfa283bbd8a
--- /dev/null
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -0,0 +1,511 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Linux driver model glue for the SDIO device, reset & fw upload
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com>
+ * Dirk Brandewie <dirk.j.brandewie@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This 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.
+ *
+ *
+ * See i2400m-sdio.h for a general description of this driver.
+ *
+ * This file implements driver model glue, and hook ups for the
+ * generic driver to implement the bus-specific functions (device
+ * communication setup/tear down, firmware upload and resetting).
+ *
+ * ROADMAP
+ *
+ * i2400m_probe()
+ * alloc_netdev()
+ * i2400ms_netdev_setup()
+ * i2400ms_init()
+ * i2400m_netdev_setup()
+ * i2400ms_enable_function()
+ * i2400m_setup()
+ *
+ * i2400m_remove()
+ * i2400m_release()
+ * free_netdev(net_dev)
+ *
+ * i2400ms_bus_reset() Called by i2400m->bus_reset
+ * __i2400ms_reset()
+ * __i2400ms_send_barker()
+ *
+ * i2400ms_bus_dev_start() Called by i2400m_dev_start() [who is
+ * i2400ms_tx_setup() called by i2400m_setup()]
+ * i2400ms_rx_setup()
+ *
+ * i2400ms_bus_dev_stop() Called by i2400m_dev_stop() [who is
+ * i2400ms_rx_release() is called by i2400m_release()]
+ * i2400ms_tx_release()
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+#include "i2400m-sdio.h"
+#include <linux/wimax/i2400m.h>
+
+#define D_SUBMODULE main
+#include "sdio-debug-levels.h"
+
+/* IOE WiMAX function timeout in seconds */
+static int ioe_timeout = 2;
+module_param(ioe_timeout, int, 0);
+
+/* Our firmware file name */
+#define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-" I2400M_FW_VERSION ".sbcf"
+
+/*
+ * Enable the SDIO function
+ *
+ * Tries to enable the SDIO function; might fail if it is still not
+ * ready (in some hardware, the SDIO WiMAX function is only enabled
+ * when we ask it to explicitly doing). Tries until a timeout is
+ * reached.
+ *
+ * The reverse of this is...sdio_disable_function()
+ *
+ * Returns: 0 if the SDIO function was enabled, < 0 errno code on
+ * error (-ENODEV when it was unable to enable the function).
+ */
+static
+int i2400ms_enable_function(struct sdio_func *func)
+{
+ u64 timeout;
+ int err;
+ struct device *dev = &func->dev;
+
+ d_fnstart(3, dev, "(func %p)\n", func);
+ /* Setup timeout (FIXME: This needs to read the CIS table to
+ * get a real timeout) and then wait for the device to signal
+ * it is ready */
+ timeout = get_jiffies_64() + ioe_timeout * HZ;
+ err = -ENODEV;
+ while (err != 0 && time_before64(get_jiffies_64(), timeout)) {
+ sdio_claim_host(func);
+ err = sdio_enable_func(func);
+ if (0 == err) {
+ sdio_release_host(func);
+ d_printf(2, dev, "SDIO function enabled\n");
+ goto function_enabled;
+ }
+ d_printf(2, dev, "SDIO function failed to enable: %d\n", err);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ msleep(I2400MS_INIT_SLEEP_INTERVAL);
+ }
+ /* If timed out, device is not there yet -- get -ENODEV so
+ * the device driver core will retry later on. */
+ if (err == -ETIME) {
+ dev_err(dev, "Can't enable WiMAX function; "
+ " has the function been enabled?\n");
+ err = -ENODEV;
+ }
+function_enabled:
+ d_fnend(3, dev, "(func %p) = %d\n", func, err);
+ return err;
+}
+
+
+/*
+ * Setup driver resources needed to communicate with the device
+ *
+ * The fw needs some time to settle, and it was just uploaded,
+ * so give it a break first. I'd prefer to just wait for the device to
+ * send something, but seems the poking we do to enable SDIO stuff
+ * interferes with it, so just give it a break before starting...
+ */
+static
+int i2400ms_bus_dev_start(struct i2400m *i2400m)
+{
+ int result;
+ struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
+ struct sdio_func *func = i2400ms->func;
+ struct device *dev = &func->dev;
+
+ d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+ msleep(200);
+ result = i2400ms_rx_setup(i2400ms);
+ if (result < 0)
+ goto error_rx_setup;
+ result = i2400ms_tx_setup(i2400ms);
+ if (result < 0)
+ goto error_tx_setup;
+ d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
+ return result;
+
+ i2400ms_tx_release(i2400ms);
+error_tx_setup:
+ i2400ms_rx_release(i2400ms);
+error_rx_setup:
+ d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
+ return result;
+}
+
+
+static
+void i2400ms_bus_dev_stop(struct i2400m *i2400m)
+{
+ struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
+ struct sdio_func *func = i2400ms->func;
+ struct device *dev = &func->dev;
+
+ d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+ i2400ms_rx_release(i2400ms);
+ i2400ms_tx_release(i2400ms);
+ d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
+}
+
+
+/*
+ * Sends a barker buffer to the device
+ *
+ * This helper will allocate a kmalloced buffer and use it to transmit
+ * (then free it). Reason for this is that the SDIO host controller
+ * expects alignment (unknown exactly which) which the stack won't
+ * really provide and certain arches/host-controller combinations
+ * cannot use stack/vmalloc/text areas for DMA transfers.
+ */
+static
+int __i2400ms_send_barker(struct i2400ms *i2400ms,
+ const __le32 *barker, size_t barker_size)
+{
+ int ret;
+ struct sdio_func *func = i2400ms->func;
+ struct device *dev = &func->dev;
+ void *buffer;
+
+ ret = -ENOMEM;
+ buffer = kmalloc(I2400MS_BLK_SIZE, GFP_KERNEL);
+ if (buffer == NULL)
+ goto error_kzalloc;
+
+ memcpy(buffer, barker, barker_size);
+ sdio_claim_host(func);
+ ret = sdio_memcpy_toio(func, 0, buffer, I2400MS_BLK_SIZE);
+ sdio_release_host(func);
+
+ if (ret < 0)
+ d_printf(0, dev, "E: barker error: %d\n", ret);
+
+ kfree(buffer);
+error_kzalloc:
+ return ret;
+}
+
+
+/*
+ * Reset a device at different levels (warm, cold or bus)
+ *
+ * @i2400ms: device descriptor
+ * @reset_type: soft, warm or bus reset (I2400M_RT_WARM/SOFT/BUS)
+ *
+ * FIXME: not tested -- need to confirm expected effects
+ *
+ * Warm and cold resets get an SDIO reset if they fail (unimplemented)
+ *
+ * Warm reset:
+ *
+ * The device will be fully reset internally, but won't be
+ * disconnected from the USB bus (so no reenumeration will
+ * happen). Firmware upload will be neccessary.
+ *
+ * The device will send a reboot barker in the notification endpoint
+ * that will trigger the driver to reinitialize the state
+ * automatically from notif.c:i2400m_notification_grok() into
+ * i2400m_dev_bootstrap_delayed().
+ *
+ * Cold and bus (USB) reset:
+ *
+ * The device will be fully reset internally, disconnected from the
+ * USB bus an a reenumeration will happen. Firmware upload will be
+ * neccessary. Thus, we don't do any locking or struct
+ * reinitialization, as we are going to be fully disconnected and
+ * reenumerated.
+ *
+ * Note we need to return -ENODEV if a warm reset was requested and we
+ * had to resort to a bus reset. See i2400m_op_reset(), wimax_reset()
+ * and wimax_dev->op_reset.
+ *
+ * WARNING: no driver state saved/fixed
+ */
+static
+int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
+{
+ int result;
+ struct i2400ms *i2400ms =
+ container_of(i2400m, struct i2400ms, i2400m);
+ struct device *dev = i2400m_dev(i2400m);
+ static const __le32 i2400m_WARM_BOOT_BARKER[4] = {
+ __constant_cpu_to_le32(I2400M_WARM_RESET_BARKER),
+ __constant_cpu_to_le32(I2400M_WARM_RESET_BARKER),
+ __constant_cpu_to_le32(I2400M_WARM_RESET_BARKER),
+ __constant_cpu_to_le32(I2400M_WARM_RESET_BARKER),
+ };
+ static const __le32 i2400m_COLD_BOOT_BARKER[4] = {
+ __constant_cpu_to_le32(I2400M_COLD_RESET_BARKER),
+ __constant_cpu_to_le32(I2400M_COLD_RESET_BARKER),
+ __constant_cpu_to_le32(I2400M_COLD_RESET_BARKER),
+ __constant_cpu_to_le32(I2400M_COLD_RESET_BARKER),
+ };
+
+ if (rt == I2400M_RT_WARM)
+ result = __i2400ms_send_barker(i2400ms, i2400m_WARM_BOOT_BARKER,
+ sizeof(i2400m_WARM_BOOT_BARKER));
+ else if (rt == I2400M_RT_COLD)
+ result = __i2400ms_send_barker(i2400ms, i2400m_COLD_BOOT_BARKER,
+ sizeof(i2400m_COLD_BOOT_BARKER));
+ else if (rt == I2400M_RT_BUS) {
+do_bus_reset:
+ dev_err(dev, "FIXME: SDIO bus reset not implemented\n");
+ result = rt == I2400M_RT_WARM ? -ENODEV : -ENOSYS;
+ } else
+ BUG();
+ if (result < 0 && rt != I2400M_RT_BUS) {
+ dev_err(dev, "%s reset failed (%d); trying SDIO reset\n",
+ rt == I2400M_RT_WARM ? "warm" : "cold", result);
+ rt = I2400M_RT_BUS;
+ goto do_bus_reset;
+ }
+ return result;
+}
+
+
+static
+void i2400ms_netdev_setup(struct net_device *net_dev)
+{
+ struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
+ struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
+ i2400ms_init(i2400ms);
+ i2400m_netdev_setup(net_dev);
+}
+
+
+/*
+ * Debug levels control; see debug.h
+ */
+struct d_level D_LEVEL[] = {
+ D_SUBMODULE_DEFINE(main),
+ D_SUBMODULE_DEFINE(tx),
+ D_SUBMODULE_DEFINE(rx),
+ D_SUBMODULE_DEFINE(fw),
+};
+size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
+
+
+#define __debugfs_register(prefix, name, parent) \
+do { \
+ result = d_level_register_debugfs(prefix, name, parent); \
+ if (result < 0) \
+ goto error; \
+} while (0)
+
+
+static
+int i2400ms_debugfs_add(struct i2400ms *i2400ms)
+{
+ int result;
+ struct dentry *dentry = i2400ms->i2400m.wimax_dev.debugfs_dentry;
+
+ dentry = debugfs_create_dir("i2400m-usb", dentry);
+ result = PTR_ERR(dentry);
+ if (IS_ERR(dentry)) {
+ if (result == -ENODEV)
+ result = 0; /* No debugfs support */
+ goto error;
+ }
+ i2400ms->debugfs_dentry = dentry;
+ __debugfs_register("dl_", main, dentry);
+ __debugfs_register("dl_", tx, dentry);
+ __debugfs_register("dl_", rx, dentry);
+ __debugfs_register("dl_", fw, dentry);
+
+ return 0;
+
+error:
+ debugfs_remove_recursive(i2400ms->debugfs_dentry);
+ return result;
+}
+
+
+/*
+ * Probe a i2400m interface and register it
+ *
+ * @func: SDIO function
+ * @id: SDIO device ID
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * Alloc a net device, initialize the bus-specific details and then
+ * calls the bus-generic initialization routine. That will register
+ * the wimax and netdev devices, upload the firmware [using
+ * _bus_bm_*()], call _bus_dev_start() to finalize the setup of the
+ * communication with the device and then will start to talk to it to
+ * finnish setting it up.
+ *
+ * Initialization is tricky; some instances of the hw are packed with
+ * others in a way that requires a third driver that enables the WiMAX
+ * function. In those cases, we can't enable the SDIO function and
+ * we'll return with -ENODEV. When the driver that enables the WiMAX
+ * function does its thing, it has to do a bus_rescan_devices() on the
+ * SDIO bus so this driver is called again to enumerate the WiMAX
+ * function.
+ */
+static
+int i2400ms_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ int result;
+ struct net_device *net_dev;
+ struct device *dev = &func->dev;
+ struct i2400m *i2400m;
+ struct i2400ms *i2400ms;
+
+ /* Allocate instance [calls i2400m_netdev_setup() on it]. */
+ result = -ENOMEM;
+ net_dev = alloc_netdev(sizeof(*i2400ms), "wmx%d",
+ i2400ms_netdev_setup);
+ if (net_dev == NULL) {
+ dev_err(dev, "no memory for network device instance\n");
+ goto error_alloc_netdev;
+ }
+ SET_NETDEV_DEV(net_dev, dev);
+ i2400m = net_dev_to_i2400m(net_dev);
+ i2400ms = container_of(i2400m, struct i2400ms, i2400m);
+ i2400m->wimax_dev.net_dev = net_dev;
+ i2400ms->func = func;
+ sdio_set_drvdata(func, i2400ms);
+
+ i2400m->bus_tx_block_size = I2400MS_BLK_SIZE;
+ i2400m->bus_pl_size_max = I2400MS_PL_SIZE_MAX;
+ i2400m->bus_dev_start = i2400ms_bus_dev_start;
+ i2400m->bus_dev_stop = i2400ms_bus_dev_stop;
+ i2400m->bus_tx_kick = i2400ms_bus_tx_kick;
+ i2400m->bus_reset = i2400ms_bus_reset;
+ i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send;
+ i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack;
+ i2400m->bus_fw_name = I2400MS_FW_FILE_NAME;
+ i2400m->bus_bm_mac_addr_impaired = 1;
+
+ result = i2400ms_enable_function(i2400ms->func);
+ if (result < 0) {
+ dev_err(dev, "Cannot enable SDIO function: %d\n", result);
+ goto error_func_enable;
+ }
+
+ sdio_claim_host(func);
+ result = sdio_set_block_size(func, I2400MS_BLK_SIZE);
+ if (result < 0) {
+ dev_err(dev, "Failed to set block size: %d\n", result);
+ goto error_set_blk_size;
+ }
+ sdio_release_host(func);
+
+ result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT);
+ if (result < 0) {
+ dev_err(dev, "cannot setup device: %d\n", result);
+ goto error_setup;
+ }
+
+ result = i2400ms_debugfs_add(i2400ms);
+ if (result < 0) {
+ dev_err(dev, "cannot create SDIO debugfs: %d\n",
+ result);
+ goto error_debugfs_add;
+ }
+ return 0;
+
+error_debugfs_add:
+ i2400m_release(i2400m);
+error_setup:
+ sdio_set_drvdata(func, NULL);
+ sdio_claim_host(func);
+error_set_blk_size:
+ sdio_disable_func(func);
+ sdio_release_host(func);
+error_func_enable:
+ free_netdev(net_dev);
+error_alloc_netdev:
+ return result;
+}
+
+
+static
+void i2400ms_remove(struct sdio_func *func)
+{
+ struct device *dev = &func->dev;
+ struct i2400ms *i2400ms = sdio_get_drvdata(func);
+ struct i2400m *i2400m = &i2400ms->i2400m;
+ struct net_device *net_dev = i2400m->wimax_dev.net_dev;
+
+ d_fnstart(3, dev, "SDIO func %p\n", func);
+ debugfs_remove_recursive(i2400ms->debugfs_dentry);
+ i2400m_release(i2400m);
+ sdio_set_drvdata(func, NULL);
+ sdio_claim_host(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ free_netdev(net_dev);
+ d_fnend(3, dev, "SDIO func %p\n", func);
+}
+
+enum {
+ I2400MS_INTEL_VID = 0x89,
+};
+
+static
+const struct sdio_device_id i2400ms_sdio_ids[] = {
+ /* Intel: i2400m WiMAX over SDIO */
+ { SDIO_DEVICE(I2400MS_INTEL_VID, 0x1402) },
+ { }, /* end: all zeroes */
+};
+MODULE_DEVICE_TABLE(sdio, i2400ms_sdio_ids);
+
+
+static
+struct sdio_driver i2400m_sdio_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = i2400ms_probe,
+ .remove = i2400ms_remove,
+ .id_table = i2400ms_sdio_ids,
+};
+
+
+static
+int __init i2400ms_driver_init(void)
+{
+ return sdio_register_driver(&i2400m_sdio_driver);
+}
+module_init(i2400ms_driver_init);
+
+
+static
+void __exit i2400ms_driver_exit(void)
+{
+ flush_scheduled_work(); /* for the stuff we schedule */
+ sdio_unregister_driver(&i2400m_sdio_driver);
+}
+module_exit(i2400ms_driver_exit);
+
+
+MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
+MODULE_DESCRIPTION("Intel 2400M WiMAX networking for SDIO");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(I2400MS_FW_FILE_NAME);
diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c
new file mode 100644
index 000000000000..613a88ffd651
--- /dev/null
+++ b/drivers/net/wimax/i2400m/tx.c
@@ -0,0 +1,817 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Generic (non-bus specific) TX handling
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ * - Initial implementation
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * - Rewritten to use a single FIFO to lower the memory allocation
+ * pressure and optimize cache hits when copying to the queue, as
+ * well as splitting out bus-specific code.
+ *
+ *
+ * Implements data transmission to the device; this is done through a
+ * software FIFO, as data/control frames can be coalesced (while the
+ * device is reading the previous tx transaction, others accumulate).
+ *
+ * A FIFO is used because at the end it is resource-cheaper that trying
+ * to implement scatter/gather over USB. As well, most traffic is going
+ * to be download (vs upload).
+ *
+ * The format for sending/receiving data to/from the i2400m is
+ * described in detail in rx.c:PROTOCOL FORMAT. In here we implement
+ * the transmission of that. This is split between a bus-independent
+ * part that just prepares everything and a bus-specific part that
+ * does the actual transmission over the bus to the device (in the
+ * bus-specific driver).
+ *
+ *
+ * The general format of a device-host transaction is MSG-HDR, PLD1,
+ * PLD2...PLDN, PL1, PL2,...PLN, PADDING.
+ *
+ * Because we need the send payload descriptors and then payloads and
+ * because it is kind of expensive to do scatterlists in USB (one URB
+ * per node), it becomes cheaper to append all the data to a FIFO
+ * (copying to a FIFO potentially in cache is cheaper).
+ *
+ * Then the bus-specific code takes the parts of that FIFO that are
+ * written and passes them to the device.
+ *
+ * So the concepts to keep in mind there are:
+ *
+ * We use a FIFO to queue the data in a linear buffer. We first append
+ * a MSG-HDR, space for I2400M_TX_PLD_MAX payload descriptors and then
+ * go appending payloads until we run out of space or of payload
+ * descriptors. Then we append padding to make the whole transaction a
+ * multiple of i2400m->bus_tx_block_size (as defined by the bus layer).
+ *
+ * - A TX message: a combination of a message header, payload
+ * descriptors and payloads.
+ *
+ * Open: it is marked as active (i2400m->tx_msg is valid) and we
+ * can keep adding payloads to it.
+ *
+ * Closed: we are not appending more payloads to this TX message
+ * (exahusted space in the queue, too many payloads or
+ * whichever). We have appended padding so the whole message
+ * length is aligned to i2400m->bus_tx_block_size (as set by the
+ * bus/transport layer).
+ *
+ * - Most of the time we keep a TX message open to which we append
+ * payloads.
+ *
+ * - If we are going to append and there is no more space (we are at
+ * the end of the FIFO), we close the message, mark the rest of the
+ * FIFO space unusable (skip_tail), create a new message at the
+ * beginning of the FIFO (if there is space) and append the message
+ * there.
+ *
+ * This is because we need to give linear TX messages to the bus
+ * engine. So we don't write a message to the remaining FIFO space
+ * until the tail and continue at the head of it.
+ *
+ * - We overload one of the fields in the message header to use it as
+ * 'size' of the TX message, so we can iterate over them. It also
+ * contains a flag that indicates if we have to skip it or not.
+ * When we send the buffer, we update that to its real on-the-wire
+ * value.
+ *
+ * - The MSG-HDR PLD1...PLD2 stuff has to be a size multiple of 16.
+ *
+ * It follows that if MSG-HDR says we have N messages, the whole
+ * header + descriptors is 16 + 4*N; for those to be a multiple of
+ * 16, it follows that N can be 4, 8, 12, ... (32, 48, 64, 80...
+ * bytes).
+ *
+ * So if we have only 1 payload, we have to submit a header that in
+ * all truth has space for 4.
+ *
+ * The implication is that we reserve space for 12 (64 bytes); but
+ * if we fill up only (eg) 2, our header becomes 32 bytes only. So
+ * the TX engine has to shift those 32 bytes of msg header and 2
+ * payloads and padding so that right after it the payloads start
+ * and the TX engine has to know about that.
+ *
+ * It is cheaper to move the header up than the whole payloads down.
+ *
+ * We do this in i2400m_tx_close(). See 'i2400m_msg_hdr->offset'.
+ *
+ * - Each payload has to be size-padded to 16 bytes; before appending
+ * it, we just do it.
+ *
+ * - The whole message has to be padded to i2400m->bus_tx_block_size;
+ * we do this at close time. Thus, when reserving space for the
+ * payload, we always make sure there is also free space for this
+ * padding that sooner or later will happen.
+ *
+ * When we append a message, we tell the bus specific code to kick in
+ * TXs. It will TX (in parallel) until the buffer is exhausted--hence
+ * the lockin we do. The TX code will only send a TX message at the
+ * time (which remember, might contain more than one payload). Of
+ * course, when the bus-specific driver attempts to TX a message that
+ * is still open, it gets closed first.
+ *
+ * Gee, this is messy; well a picture. In the example below we have a
+ * partially full FIFO, with a closed message ready to be delivered
+ * (with a moved message header to make sure it is size-aligned to
+ * 16), TAIL room that was unusable (and thus is marked with a message
+ * header that says 'skip this') and at the head of the buffer, an
+ * imcomplete message with a couple of payloads.
+ *
+ * N ___________________________________________________
+ * | |
+ * | TAIL room |
+ * | |
+ * | msg_hdr to skip (size |= 0x80000) |
+ * |---------------------------------------------------|-------
+ * | | /|\
+ * | | |
+ * | TX message padding | |
+ * | | |
+ * | | |
+ * |- - - - - - - - - - - - - - - - - - - - - - - - - -| |
+ * | | |
+ * | payload 1 | |
+ * | | N * tx_block_size
+ * | | |
+ * |- - - - - - - - - - - - - - - - - - - - - - - - - -| |
+ * | | |
+ * | payload 1 | |
+ * | | |
+ * | | |
+ * |- - - - - - - - - - - - - - - - - - - - - - - - - -|- -|- - - -
+ * | padding 3 /|\ | | /|\
+ * | padding 2 | | | |
+ * | pld 1 32 bytes (2 * 16) | | |
+ * | pld 0 | | | |
+ * | moved msg_hdr \|/ | \|/ |
+ * |- - - - - - - - - - - - - - - - - - - - - - - - - -|- - - |
+ * | | _PLD_SIZE
+ * | unused | |
+ * | | |
+ * |- - - - - - - - - - - - - - - - - - - - - - - - - -| |
+ * | msg_hdr (size X) [this message is closed] | \|/
+ * |===================================================|========== <=== OUT
+ * | |
+ * | |
+ * | |
+ * | Free rooom |
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * | |
+ * |===================================================|========== <=== IN
+ * | |
+ * | |
+ * | |
+ * | |
+ * | payload 1 |
+ * | |
+ * | |
+ * |- - - - - - - - - - - - - - - - - - - - - - - - - -|
+ * | |
+ * | payload 0 |
+ * | |
+ * | |
+ * |- - - - - - - - - - - - - - - - - - - - - - - - - -|
+ * | pld 11 /|\ |
+ * | ... | |
+ * | pld 1 64 bytes (2 * 16) |
+ * | pld 0 | |
+ * | msg_hdr (size X) \|/ [message is open] |
+ * 0 ---------------------------------------------------
+ *
+ *
+ * ROADMAP
+ *
+ * i2400m_tx_setup() Called by i2400m_setup
+ * i2400m_tx_release() Called by i2400m_release()
+ *
+ * i2400m_tx() Called to send data or control frames
+ * i2400m_tx_fifo_push() Allocates append-space in the FIFO
+ * i2400m_tx_new() Opens a new message in the FIFO
+ * i2400m_tx_fits() Checks if a new payload fits in the message
+ * i2400m_tx_close() Closes an open message in the FIFO
+ * i2400m_tx_skip_tail() Marks unusable FIFO tail space
+ * i2400m->bus_tx_kick()
+ *
+ * Now i2400m->bus_tx_kick() is the the bus-specific driver backend
+ * implementation; that would do:
+ *
+ * i2400m->bus_tx_kick()
+ * i2400m_tx_msg_get() Gets first message ready to go
+ * ...sends it...
+ * i2400m_tx_msg_sent() Ack the message is sent; repeat from
+ * _tx_msg_get() until it returns NULL
+ * (FIFO empty).
+ */
+#include <linux/netdevice.h>
+#include "i2400m.h"
+
+
+#define D_SUBMODULE tx
+#include "debug-levels.h"
+
+enum {
+ /**
+ * TX Buffer size
+ *
+ * Doc says maximum transaction is 16KiB. If we had 16KiB en
+ * route and 16KiB being queued, it boils down to needing
+ * 32KiB.
+ */
+ I2400M_TX_BUF_SIZE = 32768,
+ /**
+ * Message header and payload descriptors have to be 16
+ * aligned (16 + 4 * N = 16 * M). If we take that average sent
+ * packets are MTU size (~1400-~1500) it follows that we could
+ * fit at most 10-11 payloads in one transaction. To meet the
+ * alignment requirement, that means we need to leave space
+ * for 12 (64 bytes). To simplify, we leave space for that. If
+ * at the end there are less, we pad up to the nearest
+ * multiple of 16.
+ */
+ I2400M_TX_PLD_MAX = 12,
+ I2400M_TX_PLD_SIZE = sizeof(struct i2400m_msg_hdr)
+ + I2400M_TX_PLD_MAX * sizeof(struct i2400m_pld),
+ I2400M_TX_SKIP = 0x80000000,
+};
+
+#define TAIL_FULL ((void *)~(unsigned long)NULL)
+
+/*
+ * Allocate @size bytes in the TX fifo, return a pointer to it
+ *
+ * @i2400m: device descriptor
+ * @size: size of the buffer we need to allocate
+ * @padding: ensure that there is at least this many bytes of free
+ * contiguous space in the fifo. This is needed because later on
+ * we might need to add padding.
+ *
+ * Returns:
+ *
+ * Pointer to the allocated space. NULL if there is no
+ * space. TAIL_FULL if there is no space at the tail but there is at
+ * the head (Case B below).
+ *
+ * These are the two basic cases we need to keep an eye for -- it is
+ * much better explained in linux/kernel/kfifo.c, but this code
+ * basically does the same. No rocket science here.
+ *
+ * Case A Case B
+ * N ___________ ___________
+ * | tail room | | data |
+ * | | | |
+ * |<- IN ->| |<- OUT ->|
+ * | | | |
+ * | data | | room |
+ * | | | |
+ * |<- OUT ->| |<- IN ->|
+ * | | | |
+ * | head room | | data |
+ * 0 ----------- -----------
+ *
+ * We allocate only *contiguous* space.
+ *
+ * We can allocate only from 'room'. In Case B, it is simple; in case
+ * A, we only try from the tail room; if it is not enough, we just
+ * fail and return TAIL_FULL and let the caller figure out if we wants to
+ * skip the tail room and try to allocate from the head.
+ *
+ * Note:
+ *
+ * Assumes i2400m->tx_lock is taken, and we use that as a barrier
+ *
+ * The indexes keep increasing and we reset them to zero when we
+ * pop data off the queue
+ */
+static
+void *i2400m_tx_fifo_push(struct i2400m *i2400m, size_t size, size_t padding)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ size_t room, tail_room, needed_size;
+ void *ptr;
+
+ needed_size = size + padding;
+ room = I2400M_TX_BUF_SIZE - (i2400m->tx_in - i2400m->tx_out);
+ if (room < needed_size) { /* this takes care of Case B */
+ d_printf(2, dev, "fifo push %zu/%zu: no space\n",
+ size, padding);
+ return NULL;
+ }
+ /* Is there space at the tail? */
+ tail_room = I2400M_TX_BUF_SIZE - i2400m->tx_in % I2400M_TX_BUF_SIZE;
+ if (tail_room < needed_size) {
+ if (i2400m->tx_out % I2400M_TX_BUF_SIZE
+ < i2400m->tx_in % I2400M_TX_BUF_SIZE) {
+ d_printf(2, dev, "fifo push %zu/%zu: tail full\n",
+ size, padding);
+ return TAIL_FULL; /* There might be head space */
+ } else {
+ d_printf(2, dev, "fifo push %zu/%zu: no head space\n",
+ size, padding);
+ return NULL; /* There is no space */
+ }
+ }
+ ptr = i2400m->tx_buf + i2400m->tx_in % I2400M_TX_BUF_SIZE;
+ d_printf(2, dev, "fifo push %zu/%zu: at @%zu\n", size, padding,
+ i2400m->tx_in % I2400M_TX_BUF_SIZE);
+ i2400m->tx_in += size;
+ return ptr;
+}
+
+
+/*
+ * Mark the tail of the FIFO buffer as 'to-skip'
+ *
+ * We should never hit the BUG_ON() because all the sizes we push to
+ * the FIFO are padded to be a multiple of 16 -- the size of *msg
+ * (I2400M_PL_PAD for the payloads, I2400M_TX_PLD_SIZE for the
+ * header).
+ *
+ * Note:
+ *
+ * Assumes i2400m->tx_lock is taken, and we use that as a barrier
+ */
+static
+void i2400m_tx_skip_tail(struct i2400m *i2400m)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ size_t tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE;
+ size_t tail_room = I2400M_TX_BUF_SIZE - tx_in;
+ struct i2400m_msg_hdr *msg = i2400m->tx_buf + tx_in;
+ BUG_ON(tail_room < sizeof(*msg));
+ msg->size = tail_room | I2400M_TX_SKIP;
+ d_printf(2, dev, "skip tail: skipping %zu bytes @%zu\n",
+ tail_room, tx_in);
+ i2400m->tx_in += tail_room;
+}
+
+
+/*
+ * Check if a skb will fit in the TX queue's current active TX
+ * message (if there are still descriptors left unused).
+ *
+ * Returns:
+ * 0 if the message won't fit, 1 if it will.
+ *
+ * Note:
+ *
+ * Assumes a TX message is active (i2400m->tx_msg).
+ *
+ * Assumes i2400m->tx_lock is taken, and we use that as a barrier
+ */
+static
+unsigned i2400m_tx_fits(struct i2400m *i2400m)
+{
+ struct i2400m_msg_hdr *msg_hdr = i2400m->tx_msg;
+ return le16_to_cpu(msg_hdr->num_pls) < I2400M_TX_PLD_MAX;
+
+}
+
+
+/*
+ * Start a new TX message header in the queue.
+ *
+ * Reserve memory from the base FIFO engine and then just initialize
+ * the message header.
+ *
+ * We allocate the biggest TX message header we might need (one that'd
+ * fit I2400M_TX_PLD_MAX payloads) -- when it is closed it will be
+ * 'ironed it out' and the unneeded parts removed.
+ *
+ * NOTE:
+ *
+ * Assumes that the previous message is CLOSED (eg: either
+ * there was none or 'i2400m_tx_close()' was called on it).
+ *
+ * Assumes i2400m->tx_lock is taken, and we use that as a barrier
+ */
+static
+void i2400m_tx_new(struct i2400m *i2400m)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ struct i2400m_msg_hdr *tx_msg;
+ BUG_ON(i2400m->tx_msg != NULL);
+try_head:
+ tx_msg = i2400m_tx_fifo_push(i2400m, I2400M_TX_PLD_SIZE, 0);
+ if (tx_msg == NULL)
+ goto out;
+ else if (tx_msg == TAIL_FULL) {
+ i2400m_tx_skip_tail(i2400m);
+ d_printf(2, dev, "new TX message: tail full, trying head\n");
+ goto try_head;
+ }
+ memset(tx_msg, 0, I2400M_TX_PLD_SIZE);
+ tx_msg->size = I2400M_TX_PLD_SIZE;
+out:
+ i2400m->tx_msg = tx_msg;
+ d_printf(2, dev, "new TX message: %p @%zu\n",
+ tx_msg, (void *) tx_msg - i2400m->tx_buf);
+}
+
+
+/*
+ * Finalize the current TX message header
+ *
+ * Sets the message header to be at the proper location depending on
+ * how many descriptors we have (check documentation at the file's
+ * header for more info on that).
+ *
+ * Appends padding bytes to make sure the whole TX message (counting
+ * from the 'relocated' message header) is aligned to
+ * tx_block_size. We assume the _append() code has left enough space
+ * in the FIFO for that. If there are no payloads, just pass, as it
+ * won't be transferred.
+ *
+ * The amount of padding bytes depends on how many payloads are in the
+ * TX message, as the "msg header and payload descriptors" will be
+ * shifted up in the buffer.
+ */
+static
+void i2400m_tx_close(struct i2400m *i2400m)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ struct i2400m_msg_hdr *tx_msg = i2400m->tx_msg;
+ struct i2400m_msg_hdr *tx_msg_moved;
+ size_t aligned_size, padding, hdr_size;
+ void *pad_buf;
+
+ if (tx_msg->size & I2400M_TX_SKIP) /* a skipper? nothing to do */
+ goto out;
+
+ /* Relocate the message header
+ *
+ * Find the current header size, align it to 16 and if we need
+ * to move it so the tail is next to the payloads, move it and
+ * set the offset.
+ *
+ * If it moved, this header is good only for transmission; the
+ * original one (it is kept if we moved) is still used to
+ * figure out where the next TX message starts (and where the
+ * offset to the moved header is).
+ */
+ hdr_size = sizeof(*tx_msg)
+ + le16_to_cpu(tx_msg->num_pls) * sizeof(tx_msg->pld[0]);
+ hdr_size = ALIGN(hdr_size, I2400M_PL_PAD);
+ tx_msg->offset = I2400M_TX_PLD_SIZE - hdr_size;
+ tx_msg_moved = (void *) tx_msg + tx_msg->offset;
+ memmove(tx_msg_moved, tx_msg, hdr_size);
+ tx_msg_moved->size -= tx_msg->offset;
+ /*
+ * Now figure out how much we have to add to the (moved!)
+ * message so the size is a multiple of i2400m->bus_tx_block_size.
+ */
+ aligned_size = ALIGN(tx_msg_moved->size, i2400m->bus_tx_block_size);
+ padding = aligned_size - tx_msg_moved->size;
+ if (padding > 0) {
+ pad_buf = i2400m_tx_fifo_push(i2400m, padding, 0);
+ if (unlikely(WARN_ON(pad_buf == NULL
+ || pad_buf == TAIL_FULL))) {
+ /* This should not happen -- append should verify
+ * there is always space left at least to append
+ * tx_block_size */
+ dev_err(dev,
+ "SW BUG! Possible data leakage from memory the "
+ "device should not read for padding - "
+ "size %lu aligned_size %zu tx_buf %p in "
+ "%zu out %zu\n",
+ (unsigned long) tx_msg_moved->size,
+ aligned_size, i2400m->tx_buf, i2400m->tx_in,
+ i2400m->tx_out);
+ } else
+ memset(pad_buf, 0xad, padding);
+ }
+ tx_msg_moved->padding = cpu_to_le16(padding);
+ tx_msg_moved->size += padding;
+ if (tx_msg != tx_msg_moved)
+ tx_msg->size += padding;
+out:
+ i2400m->tx_msg = NULL;
+}
+
+
+/**
+ * i2400m_tx - send the data in a buffer to the device
+ *
+ * @buf: pointer to the buffer to transmit
+ *
+ * @buf_len: buffer size
+ *
+ * @pl_type: type of the payload we are sending.
+ *
+ * Returns:
+ * 0 if ok, < 0 errno code on error (-ENOSPC, if there is no more
+ * room for the message in the queue).
+ *
+ * Appends the buffer to the TX FIFO and notifies the bus-specific
+ * part of the driver that there is new data ready to transmit.
+ * Once this function returns, the buffer has been copied, so it can
+ * be reused.
+ *
+ * The steps followed to append are explained in detail in the file
+ * header.
+ *
+ * Whenever we write to a message, we increase msg->size, so it
+ * reflects exactly how big the message is. This is needed so that if
+ * we concatenate two messages before they can be sent, the code that
+ * sends the messages can find the boundaries (and it will replace the
+ * size with the real barker before sending).
+ *
+ * Note:
+ *
+ * Cold and warm reset payloads need to be sent as a single
+ * payload, so we handle that.
+ */
+int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
+ enum i2400m_pt pl_type)
+{
+ int result = -ENOSPC;
+ struct device *dev = i2400m_dev(i2400m);
+ unsigned long flags;
+ size_t padded_len;
+ void *ptr;
+ unsigned is_singleton = pl_type == I2400M_PT_RESET_WARM
+ || pl_type == I2400M_PT_RESET_COLD;
+
+ d_fnstart(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u)\n",
+ i2400m, buf, buf_len, pl_type);
+ padded_len = ALIGN(buf_len, I2400M_PL_PAD);
+ d_printf(5, dev, "padded_len %zd buf_len %zd\n", padded_len, buf_len);
+ /* If there is no current TX message, create one; if the
+ * current one is out of payload slots or we have a singleton,
+ * close it and start a new one */
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
+try_new:
+ if (unlikely(i2400m->tx_msg == NULL))
+ i2400m_tx_new(i2400m);
+ else if (unlikely(!i2400m_tx_fits(i2400m)
+ || (is_singleton && i2400m->tx_msg->num_pls != 0))) {
+ d_printf(2, dev, "closing TX message (fits %u singleton "
+ "%u num_pls %u)\n", i2400m_tx_fits(i2400m),
+ is_singleton, i2400m->tx_msg->num_pls);
+ i2400m_tx_close(i2400m);
+ i2400m_tx_new(i2400m);
+ }
+ if (i2400m->tx_msg->size + padded_len > I2400M_TX_BUF_SIZE / 2) {
+ d_printf(2, dev, "TX: message too big, going new\n");
+ i2400m_tx_close(i2400m);
+ i2400m_tx_new(i2400m);
+ }
+ if (i2400m->tx_msg == NULL)
+ goto error_tx_new;
+ /* So we have a current message header; now append space for
+ * the message -- if there is not enough, try the head */
+ ptr = i2400m_tx_fifo_push(i2400m, padded_len,
+ i2400m->bus_tx_block_size);
+ if (ptr == TAIL_FULL) { /* Tail is full, try head */
+ d_printf(2, dev, "pl append: tail full\n");
+ i2400m_tx_close(i2400m);
+ i2400m_tx_skip_tail(i2400m);
+ goto try_new;
+ } else if (ptr == NULL) { /* All full */
+ result = -ENOSPC;
+ d_printf(2, dev, "pl append: all full\n");
+ } else { /* Got space, copy it, set padding */
+ struct i2400m_msg_hdr *tx_msg = i2400m->tx_msg;
+ unsigned num_pls = le16_to_cpu(tx_msg->num_pls);
+ memcpy(ptr, buf, buf_len);
+ memset(ptr + buf_len, 0xad, padded_len - buf_len);
+ i2400m_pld_set(&tx_msg->pld[num_pls], buf_len, pl_type);
+ d_printf(3, dev, "pld 0x%08x (type 0x%1x len 0x%04zx\n",
+ le32_to_cpu(tx_msg->pld[num_pls].val),
+ pl_type, buf_len);
+ tx_msg->num_pls = le16_to_cpu(num_pls+1);
+ tx_msg->size += padded_len;
+ d_printf(2, dev, "TX: appended %zu b (up to %u b) pl #%u \n",
+ padded_len, tx_msg->size, num_pls+1);
+ d_printf(2, dev,
+ "TX: appended hdr @%zu %zu b pl #%u @%zu %zu/%zu b\n",
+ (void *)tx_msg - i2400m->tx_buf, (size_t)tx_msg->size,
+ num_pls+1, ptr - i2400m->tx_buf, buf_len, padded_len);
+ result = 0;
+ if (is_singleton)
+ i2400m_tx_close(i2400m);
+ }
+error_tx_new:
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+ i2400m->bus_tx_kick(i2400m); /* always kick, might free up space */
+ d_fnend(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u) = %d\n",
+ i2400m, buf, buf_len, pl_type, result);
+ return result;
+}
+EXPORT_SYMBOL_GPL(i2400m_tx);
+
+
+/**
+ * i2400m_tx_msg_get - Get the first TX message in the FIFO to start sending it
+ *
+ * @i2400m: device descriptors
+ * @bus_size: where to place the size of the TX message
+ *
+ * Called by the bus-specific driver to get the first TX message at
+ * the FIF that is ready for transmission.
+ *
+ * It sets the state in @i2400m to indicate the bus-specific driver is
+ * transfering that message (i2400m->tx_msg_size).
+ *
+ * Once the transfer is completed, call i2400m_tx_msg_sent().
+ *
+ * Notes:
+ *
+ * The size of the TX message to be transmitted might be smaller than
+ * that of the TX message in the FIFO (in case the header was
+ * shorter). Hence, we copy it in @bus_size, for the bus layer to
+ * use. We keep the message's size in i2400m->tx_msg_size so that
+ * when the bus later is done transferring we know how much to
+ * advance the fifo.
+ *
+ * We collect statistics here as all the data is available and we
+ * assume it is going to work [see i2400m_tx_msg_sent()].
+ */
+struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *i2400m,
+ size_t *bus_size)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ struct i2400m_msg_hdr *tx_msg, *tx_msg_moved;
+ unsigned long flags, pls;
+
+ d_fnstart(3, dev, "(i2400m %p bus_size %p)\n", i2400m, bus_size);
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
+skip:
+ tx_msg_moved = NULL;
+ if (i2400m->tx_in == i2400m->tx_out) { /* Empty FIFO? */
+ i2400m->tx_in = 0;
+ i2400m->tx_out = 0;
+ d_printf(2, dev, "TX: FIFO empty: resetting\n");
+ goto out_unlock;
+ }
+ tx_msg = i2400m->tx_buf + i2400m->tx_out % I2400M_TX_BUF_SIZE;
+ if (tx_msg->size & I2400M_TX_SKIP) { /* skip? */
+ d_printf(2, dev, "TX: skip: msg @%zu (%zu b)\n",
+ i2400m->tx_out % I2400M_TX_BUF_SIZE,
+ (size_t) tx_msg->size & ~I2400M_TX_SKIP);
+ i2400m->tx_out += tx_msg->size & ~I2400M_TX_SKIP;
+ goto skip;
+ }
+
+ if (tx_msg->num_pls == 0) { /* No payloads? */
+ if (tx_msg == i2400m->tx_msg) { /* open, we are done */
+ d_printf(2, dev,
+ "TX: FIFO empty: open msg w/o payloads @%zu\n",
+ (void *) tx_msg - i2400m->tx_buf);
+ tx_msg = NULL;
+ goto out_unlock;
+ } else { /* closed, skip it */
+ d_printf(2, dev,
+ "TX: skip msg w/o payloads @%zu (%zu b)\n",
+ (void *) tx_msg - i2400m->tx_buf,
+ (size_t) tx_msg->size);
+ i2400m->tx_out += tx_msg->size & ~I2400M_TX_SKIP;
+ goto skip;
+ }
+ }
+ if (tx_msg == i2400m->tx_msg) /* open msg? */
+ i2400m_tx_close(i2400m);
+
+ /* Now we have a valid TX message (with payloads) to TX */
+ tx_msg_moved = (void *) tx_msg + tx_msg->offset;
+ i2400m->tx_msg_size = tx_msg->size;
+ *bus_size = tx_msg_moved->size;
+ d_printf(2, dev, "TX: pid %d msg hdr at @%zu offset +@%zu "
+ "size %zu bus_size %zu\n",
+ current->pid, (void *) tx_msg - i2400m->tx_buf,
+ (size_t) tx_msg->offset, (size_t) tx_msg->size,
+ (size_t) tx_msg_moved->size);
+ tx_msg_moved->barker = le32_to_cpu(I2400M_H2D_PREVIEW_BARKER);
+ tx_msg_moved->sequence = le32_to_cpu(i2400m->tx_sequence++);
+
+ pls = le32_to_cpu(tx_msg_moved->num_pls);
+ i2400m->tx_pl_num += pls; /* Update stats */
+ if (pls > i2400m->tx_pl_max)
+ i2400m->tx_pl_max = pls;
+ if (pls < i2400m->tx_pl_min)
+ i2400m->tx_pl_min = pls;
+ i2400m->tx_num++;
+ i2400m->tx_size_acc += *bus_size;
+ if (*bus_size < i2400m->tx_size_min)
+ i2400m->tx_size_min = *bus_size;
+ if (*bus_size > i2400m->tx_size_max)
+ i2400m->tx_size_max = *bus_size;
+out_unlock:
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+ d_fnstart(3, dev, "(i2400m %p bus_size %p [%zu]) = %p\n",
+ i2400m, bus_size, *bus_size, tx_msg_moved);
+ return tx_msg_moved;
+}
+EXPORT_SYMBOL_GPL(i2400m_tx_msg_get);
+
+
+/**
+ * i2400m_tx_msg_sent - indicate the transmission of a TX message
+ *
+ * @i2400m: device descriptor
+ *
+ * Called by the bus-specific driver when a message has been sent;
+ * this pops it from the FIFO; and as there is space, start the queue
+ * in case it was stopped.
+ *
+ * Should be called even if the message send failed and we are
+ * dropping this TX message.
+ */
+void i2400m_tx_msg_sent(struct i2400m *i2400m)
+{
+ unsigned n;
+ unsigned long flags;
+ struct device *dev = i2400m_dev(i2400m);
+
+ d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
+ i2400m->tx_out += i2400m->tx_msg_size;
+ d_printf(2, dev, "TX: sent %zu b\n", (size_t) i2400m->tx_msg_size);
+ i2400m->tx_msg_size = 0;
+ BUG_ON(i2400m->tx_out > i2400m->tx_in);
+ /* level them FIFO markers off */
+ n = i2400m->tx_out / I2400M_TX_BUF_SIZE;
+ i2400m->tx_out %= I2400M_TX_BUF_SIZE;
+ i2400m->tx_in -= n * I2400M_TX_BUF_SIZE;
+ netif_start_queue(i2400m->wimax_dev.net_dev);
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+ d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
+}
+EXPORT_SYMBOL_GPL(i2400m_tx_msg_sent);
+
+
+/**
+ * i2400m_tx_setup - Initialize the TX queue and infrastructure
+ *
+ * Make sure we reset the TX sequence to zero, as when this function
+ * is called, the firmware has been just restarted.
+ */
+int i2400m_tx_setup(struct i2400m *i2400m)
+{
+ int result;
+
+ /* Do this here only once -- can't do on
+ * i2400m_hard_start_xmit() as we'll cause race conditions if
+ * the WS was scheduled on another CPU */
+ INIT_WORK(&i2400m->wake_tx_ws, i2400m_wake_tx_work);
+
+ i2400m->tx_sequence = 0;
+ i2400m->tx_buf = kmalloc(I2400M_TX_BUF_SIZE, GFP_KERNEL);
+ if (i2400m->tx_buf == NULL)
+ result = -ENOMEM;
+ else
+ result = 0;
+ /* Huh? the bus layer has to define this... */
+ BUG_ON(i2400m->bus_tx_block_size == 0);
+ return result;
+
+}
+
+
+/**
+ * i2400m_tx_release - Tear down the TX queue and infrastructure
+ */
+void i2400m_tx_release(struct i2400m *i2400m)
+{
+ kfree(i2400m->tx_buf);
+}
diff --git a/drivers/net/wimax/i2400m/usb-debug-levels.h b/drivers/net/wimax/i2400m/usb-debug-levels.h
new file mode 100644
index 000000000000..e4358bd880be
--- /dev/null
+++ b/drivers/net/wimax/i2400m/usb-debug-levels.h
@@ -0,0 +1,42 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Debug levels control file for the i2400m-usb module
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This 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.
+ */
+#ifndef __debug_levels__h__
+#define __debug_levels__h__
+
+/* Maximum compile and run time debug level for all submodules */
+#define D_MODULENAME i2400m_usb
+#define D_MASTER CONFIG_WIMAX_I2400M_DEBUG_LEVEL
+
+#include <linux/wimax/debug.h>
+
+/* List of all the enabled modules */
+enum d_module {
+ D_SUBMODULE_DECLARE(usb),
+ D_SUBMODULE_DECLARE(fw),
+ D_SUBMODULE_DECLARE(notif),
+ D_SUBMODULE_DECLARE(rx),
+ D_SUBMODULE_DECLARE(tx),
+};
+
+
+#endif /* #ifndef __debug_levels__h__ */
diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c
new file mode 100644
index 000000000000..5ad287c228b8
--- /dev/null
+++ b/drivers/net/wimax/i2400m/usb-fw.c
@@ -0,0 +1,340 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Firmware uploader's USB specifics
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * - Initial implementation
+ *
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * - bus generic/specific split
+ *
+ * THE PROCEDURE
+ *
+ * See fw.c for the generic description of this procedure.
+ *
+ * This file implements only the USB specifics. It boils down to how
+ * to send a command and waiting for an acknowledgement from the
+ * device.
+ *
+ * This code (and process) is single threaded. It assumes it is the
+ * only thread poking around (guaranteed by fw.c).
+ *
+ * COMMAND EXECUTION
+ *
+ * A write URB is posted with the buffer to the bulk output endpoint.
+ *
+ * ACK RECEPTION
+ *
+ * We just post a URB to the notification endpoint and wait for
+ * data. We repeat until we get all the data we expect (as indicated
+ * by the call from the bus generic code).
+ *
+ * The data is not read from the bulk in endpoint for boot mode.
+ *
+ * ROADMAP
+ *
+ * i2400mu_bus_bm_cmd_send
+ * i2400m_bm_cmd_prepare...
+ * i2400mu_tx_bulk_out
+ *
+ * i2400mu_bus_bm_wait_for_ack
+ * i2400m_notif_submit
+ */
+#include <linux/usb.h>
+#include "i2400m-usb.h"
+
+
+#define D_SUBMODULE fw
+#include "usb-debug-levels.h"
+
+
+/*
+ * Synchronous write to the device
+ *
+ * Takes care of updating EDC counts and thus, handle device errors.
+ */
+static
+ssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size)
+{
+ int result;
+ struct device *dev = &i2400mu->usb_iface->dev;
+ int len;
+ struct usb_endpoint_descriptor *epd;
+ int pipe, do_autopm = 1;
+
+ result = usb_autopm_get_interface(i2400mu->usb_iface);
+ if (result < 0) {
+ dev_err(dev, "BM-CMD: can't get autopm: %d\n", result);
+ do_autopm = 0;
+ }
+ epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_BULK_OUT);
+ pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
+retry:
+ result = usb_bulk_msg(i2400mu->usb_dev, pipe, buf, buf_size, &len, HZ);
+ switch (result) {
+ case 0:
+ if (len != buf_size) {
+ dev_err(dev, "BM-CMD: short write (%u B vs %zu "
+ "expected)\n", len, buf_size);
+ result = -EIO;
+ break;
+ }
+ result = len;
+ break;
+ case -EINVAL: /* while removing driver */
+ case -ENODEV: /* dev disconnect ... */
+ case -ENOENT: /* just ignore it */
+ case -ESHUTDOWN: /* and exit */
+ case -ECONNRESET:
+ result = -ESHUTDOWN;
+ break;
+ case -ETIMEDOUT: /* bah... */
+ break;
+ default: /* any other? */
+ if (edc_inc(&i2400mu->urb_edc,
+ EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "BM-CMD: maximum errors in "
+ "URB exceeded; resetting device\n");
+ usb_queue_reset_device(i2400mu->usb_iface);
+ result = -ENODEV;
+ break;
+ }
+ dev_err(dev, "BM-CMD: URB error %d, retrying\n",
+ result);
+ goto retry;
+ }
+ result = len;
+ if (do_autopm)
+ usb_autopm_put_interface(i2400mu->usb_iface);
+ return result;
+}
+
+
+/*
+ * Send a boot-mode command over the bulk-out pipe
+ *
+ * Command can be a raw command, which requires no preparation (and
+ * which might not even be following the command format). Checks that
+ * the right amount of data was transfered.
+ *
+ * To satisfy USB requirements (no onstack, vmalloc or in data segment
+ * buffers), we copy the command to i2400m->bm_cmd_buf and send it from
+ * there.
+ *
+ * @flags: pass thru from i2400m_bm_cmd()
+ * @return: cmd_size if ok, < 0 errno code on error.
+ */
+ssize_t i2400mu_bus_bm_cmd_send(struct i2400m *i2400m,
+ const struct i2400m_bootrom_header *_cmd,
+ size_t cmd_size, int flags)
+{
+ ssize_t result;
+ struct device *dev = i2400m_dev(i2400m);
+ struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
+ int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd);
+ struct i2400m_bootrom_header *cmd;
+ size_t cmd_size_a = ALIGN(cmd_size, 16); /* USB restriction */
+
+ d_fnstart(8, dev, "(i2400m %p cmd %p size %zu)\n",
+ i2400m, _cmd, cmd_size);
+ result = -E2BIG;
+ if (cmd_size > I2400M_BM_CMD_BUF_SIZE)
+ goto error_too_big;
+ memcpy(i2400m->bm_cmd_buf, _cmd, cmd_size);
+ cmd = i2400m->bm_cmd_buf;
+ if (cmd_size_a > cmd_size) /* Zero pad space */
+ memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size);
+ if ((flags & I2400M_BM_CMD_RAW) == 0) {
+ if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0))
+ dev_warn(dev, "SW BUG: response_required == 0\n");
+ i2400m_bm_cmd_prepare(cmd);
+ }
+ result = i2400mu_tx_bulk_out(i2400mu, i2400m->bm_cmd_buf, cmd_size);
+ if (result < 0) {
+ dev_err(dev, "boot-mode cmd %d: cannot send: %zd\n",
+ opcode, result);
+ goto error_cmd_send;
+ }
+ if (result != cmd_size) { /* all was transferred? */
+ dev_err(dev, "boot-mode cmd %d: incomplete transfer "
+ "(%zu vs %zu submitted)\n", opcode, result, cmd_size);
+ result = -EIO;
+ goto error_cmd_size;
+ }
+error_cmd_size:
+error_cmd_send:
+error_too_big:
+ d_fnend(8, dev, "(i2400m %p cmd %p size %zu) = %zd\n",
+ i2400m, _cmd, cmd_size, result);
+ return result;
+}
+
+
+static
+void __i2400mu_bm_notif_cb(struct urb *urb)
+{
+ complete(urb->context);
+}
+
+
+/*
+ * submit a read to the notification endpoint
+ *
+ * @i2400m: device descriptor
+ * @urb: urb to use
+ * @completion: completion varible to complete when done
+ *
+ * Data is always read to i2400m->bm_ack_buf
+ */
+static
+int i2400mu_notif_submit(struct i2400mu *i2400mu, struct urb *urb,
+ struct completion *completion)
+{
+ struct i2400m *i2400m = &i2400mu->i2400m;
+ struct usb_endpoint_descriptor *epd;
+ int pipe;
+
+ epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_NOTIFICATION);
+ pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress);
+ usb_fill_int_urb(urb, i2400mu->usb_dev, pipe,
+ i2400m->bm_ack_buf, I2400M_BM_ACK_BUF_SIZE,
+ __i2400mu_bm_notif_cb, completion,
+ epd->bInterval);
+ return usb_submit_urb(urb, GFP_KERNEL);
+}
+
+
+/*
+ * Read an ack from the notification endpoint
+ *
+ * @i2400m:
+ * @_ack: pointer to where to store the read data
+ * @ack_size: how many bytes we should read
+ *
+ * Returns: < 0 errno code on error; otherwise, amount of received bytes.
+ *
+ * Submits a notification read, appends the read data to the given ack
+ * buffer and then repeats (until @ack_size bytes have been
+ * received).
+ */
+ssize_t i2400mu_bus_bm_wait_for_ack(struct i2400m *i2400m,
+ struct i2400m_bootrom_header *_ack,
+ size_t ack_size)
+{
+ ssize_t result = -ENOMEM;
+ struct device *dev = i2400m_dev(i2400m);
+ struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
+ struct urb notif_urb;
+ void *ack = _ack;
+ size_t offset, len;
+ long val;
+ int do_autopm = 1;
+ DECLARE_COMPLETION_ONSTACK(notif_completion);
+
+ d_fnstart(8, dev, "(i2400m %p ack %p size %zu)\n",
+ i2400m, ack, ack_size);
+ BUG_ON(_ack == i2400m->bm_ack_buf);
+ result = usb_autopm_get_interface(i2400mu->usb_iface);
+ if (result < 0) {
+ dev_err(dev, "BM-ACK: can't get autopm: %d\n", (int) result);
+ do_autopm = 0;
+ }
+ usb_init_urb(&notif_urb); /* ready notifications */
+ usb_get_urb(&notif_urb);
+ offset = 0;
+ while (offset < ack_size) {
+ init_completion(&notif_completion);
+ result = i2400mu_notif_submit(i2400mu, &notif_urb,
+ &notif_completion);
+ if (result < 0)
+ goto error_notif_urb_submit;
+ val = wait_for_completion_interruptible_timeout(
+ &notif_completion, HZ);
+ if (val == 0) {
+ result = -ETIMEDOUT;
+ usb_kill_urb(&notif_urb); /* Timedout */
+ goto error_notif_wait;
+ }
+ if (val == -ERESTARTSYS) {
+ result = -EINTR; /* Interrupted */
+ usb_kill_urb(&notif_urb);
+ goto error_notif_wait;
+ }
+ result = notif_urb.status; /* How was the ack? */
+ switch (result) {
+ case 0:
+ break;
+ case -EINVAL: /* while removing driver */
+ case -ENODEV: /* dev disconnect ... */
+ case -ENOENT: /* just ignore it */
+ case -ESHUTDOWN: /* and exit */
+ case -ECONNRESET:
+ result = -ESHUTDOWN;
+ goto error_dev_gone;
+ default: /* any other? */
+ usb_kill_urb(&notif_urb); /* Timedout */
+ if (edc_inc(&i2400mu->urb_edc,
+ EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME))
+ goto error_exceeded;
+ dev_err(dev, "BM-ACK: URB error %d, "
+ "retrying\n", notif_urb.status);
+ continue; /* retry */
+ }
+ if (notif_urb.actual_length == 0) {
+ d_printf(6, dev, "ZLP received, retrying\n");
+ continue;
+ }
+ /* Got data, append it to the buffer */
+ len = min(ack_size - offset, (size_t) notif_urb.actual_length);
+ memcpy(ack + offset, i2400m->bm_ack_buf, len);
+ offset += len;
+ }
+ result = offset;
+error_notif_urb_submit:
+error_notif_wait:
+error_dev_gone:
+out:
+ if (do_autopm)
+ usb_autopm_put_interface(i2400mu->usb_iface);
+ d_fnend(8, dev, "(i2400m %p ack %p size %zu) = %zd\n",
+ i2400m, ack, ack_size, result);
+ return result;
+
+error_exceeded:
+ dev_err(dev, "bm: maximum errors in notification URB exceeded; "
+ "resetting device\n");
+ usb_queue_reset_device(i2400mu->usb_iface);
+ goto out;
+}
diff --git a/drivers/net/wimax/i2400m/usb-notif.c b/drivers/net/wimax/i2400m/usb-notif.c
new file mode 100644
index 000000000000..9702c22b2497
--- /dev/null
+++ b/drivers/net/wimax/i2400m/usb-notif.c
@@ -0,0 +1,269 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m over USB
+ * Notification handling
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * - Initial implementation
+ *
+ *
+ * The notification endpoint is active when the device is not in boot
+ * mode; in here we just read and get notifications; based on those,
+ * we act to either reinitialize the device after a reboot or to
+ * submit a RX request.
+ *
+ * ROADMAP
+ *
+ * i2400mu_usb_notification_setup()
+ *
+ * i2400mu_usb_notification_release()
+ *
+ * i2400mu_usb_notification_cb() Called when a URB is ready
+ * i2400mu_notif_grok()
+ * i2400m_dev_reset_handle()
+ * i2400mu_rx_kick()
+ */
+#include <linux/usb.h>
+#include "i2400m-usb.h"
+
+
+#define D_SUBMODULE notif
+#include "usb-debug-levels.h"
+
+
+static const
+__le32 i2400m_ZERO_BARKER[4] = { 0, 0, 0, 0 };
+
+
+/*
+ * Process a received notification
+ *
+ * In normal operation mode, we can only receive two types of payloads
+ * on the notification endpoint:
+ *
+ * - a reboot barker, we do a bootstrap (the device has reseted).
+ *
+ * - a block of zeroes: there is pending data in the IN endpoint
+ */
+static
+int i2400mu_notification_grok(struct i2400mu *i2400mu, const void *buf,
+ size_t buf_len)
+{
+ int ret;
+ struct device *dev = &i2400mu->usb_iface->dev;
+ struct i2400m *i2400m = &i2400mu->i2400m;
+
+ d_fnstart(4, dev, "(i2400m %p buf %p buf_len %zu)\n",
+ i2400mu, buf, buf_len);
+ ret = -EIO;
+ if (buf_len < sizeof(i2400m_NBOOT_BARKER))
+ /* Not a bug, just ignore */
+ goto error_bad_size;
+ if (!memcmp(i2400m_NBOOT_BARKER, buf, sizeof(i2400m_NBOOT_BARKER))
+ || !memcmp(i2400m_SBOOT_BARKER, buf, sizeof(i2400m_SBOOT_BARKER)))
+ ret = i2400m_dev_reset_handle(i2400m);
+ else if (!memcmp(i2400m_ZERO_BARKER, buf, sizeof(i2400m_ZERO_BARKER))) {
+ i2400mu_rx_kick(i2400mu);
+ ret = 0;
+ } else { /* Unknown or unexpected data in the notif message */
+ char prefix[64];
+ ret = -EIO;
+ dev_err(dev, "HW BUG? Unknown/unexpected data in notification "
+ "message (%zu bytes)\n", buf_len);
+ snprintf(prefix, sizeof(prefix), "%s %s: ",
+ dev_driver_string(dev) , dev->bus_id);
+ if (buf_len > 64) {
+ print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET,
+ 8, 4, buf, 64, 0);
+ printk(KERN_ERR "%s... (only first 64 bytes "
+ "dumped)\n", prefix);
+ } else
+ print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET,
+ 8, 4, buf, buf_len, 0);
+ }
+error_bad_size:
+ d_fnend(4, dev, "(i2400m %p buf %p buf_len %zu) = %d\n",
+ i2400mu, buf, buf_len, ret);
+ return ret;
+}
+
+
+/*
+ * URB callback for the notification endpoint
+ *
+ * @urb: the urb received from the notification endpoint
+ *
+ * This function will just process the USB side of the transaction,
+ * checking everything is fine, pass the processing to
+ * i2400m_notification_grok() and resubmit the URB.
+ */
+static
+void i2400mu_notification_cb(struct urb *urb)
+{
+ int ret;
+ struct i2400mu *i2400mu = urb->context;
+ struct device *dev = &i2400mu->usb_iface->dev;
+
+ d_fnstart(4, dev, "(urb %p status %d actual_length %d)\n",
+ urb, urb->status, urb->actual_length);
+ ret = urb->status;
+ switch (ret) {
+ case 0:
+ ret = i2400mu_notification_grok(i2400mu, urb->transfer_buffer,
+ urb->actual_length);
+ if (ret == -EIO && edc_inc(&i2400mu->urb_edc, EDC_MAX_ERRORS,
+ EDC_ERROR_TIMEFRAME))
+ goto error_exceeded;
+ if (ret == -ENOMEM) /* uff...power cycle? shutdown? */
+ goto error_exceeded;
+ break;
+ case -EINVAL: /* while removing driver */
+ case -ENODEV: /* dev disconnect ... */
+ case -ENOENT: /* ditto */
+ case -ESHUTDOWN: /* URB killed */
+ case -ECONNRESET: /* disconnection */
+ goto out; /* Notify around */
+ default: /* Some error? */
+ if (edc_inc(&i2400mu->urb_edc,
+ EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME))
+ goto error_exceeded;
+ dev_err(dev, "notification: URB error %d, retrying\n",
+ urb->status);
+ }
+ usb_mark_last_busy(i2400mu->usb_dev);
+ ret = usb_submit_urb(i2400mu->notif_urb, GFP_ATOMIC);
+ switch (ret) {
+ case 0:
+ case -EINVAL: /* while removing driver */
+ case -ENODEV: /* dev disconnect ... */
+ case -ENOENT: /* ditto */
+ case -ESHUTDOWN: /* URB killed */
+ case -ECONNRESET: /* disconnection */
+ break; /* just ignore */
+ default: /* Some error? */
+ dev_err(dev, "notification: cannot submit URB: %d\n", ret);
+ goto error_submit;
+ }
+ d_fnend(4, dev, "(urb %p status %d actual_length %d) = void\n",
+ urb, urb->status, urb->actual_length);
+ return;
+
+error_exceeded:
+ dev_err(dev, "maximum errors in notification URB exceeded; "
+ "resetting device\n");
+error_submit:
+ usb_queue_reset_device(i2400mu->usb_iface);
+out:
+ d_fnend(4, dev, "(urb %p status %d actual_length %d) = void\n",
+ urb, urb->status, urb->actual_length);
+ return;
+}
+
+
+/*
+ * setup the notification endpoint
+ *
+ * @i2400m: device descriptor
+ *
+ * This procedure prepares the notification urb and handler for receiving
+ * unsolicited barkers from the device.
+ */
+int i2400mu_notification_setup(struct i2400mu *i2400mu)
+{
+ struct device *dev = &i2400mu->usb_iface->dev;
+ int usb_pipe, ret = 0;
+ struct usb_endpoint_descriptor *epd;
+ char *buf;
+
+ d_fnstart(4, dev, "(i2400m %p)\n", i2400mu);
+ buf = kmalloc(I2400MU_MAX_NOTIFICATION_LEN, GFP_KERNEL | GFP_DMA);
+ if (buf == NULL) {
+ dev_err(dev, "notification: buffer allocation failed\n");
+ ret = -ENOMEM;
+ goto error_buf_alloc;
+ }
+
+ i2400mu->notif_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!i2400mu->notif_urb) {
+ ret = -ENOMEM;
+ dev_err(dev, "notification: cannot allocate URB\n");
+ goto error_alloc_urb;
+ }
+ epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_NOTIFICATION);
+ usb_pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress);
+ usb_fill_int_urb(i2400mu->notif_urb, i2400mu->usb_dev, usb_pipe,
+ buf, I2400MU_MAX_NOTIFICATION_LEN,
+ i2400mu_notification_cb, i2400mu, epd->bInterval);
+ ret = usb_submit_urb(i2400mu->notif_urb, GFP_KERNEL);
+ if (ret != 0) {
+ dev_err(dev, "notification: cannot submit URB: %d\n", ret);
+ goto error_submit;
+ }
+ d_fnend(4, dev, "(i2400m %p) = %d\n", i2400mu, ret);
+ return ret;
+
+error_submit:
+ usb_free_urb(i2400mu->notif_urb);
+error_alloc_urb:
+ kfree(buf);
+error_buf_alloc:
+ d_fnend(4, dev, "(i2400m %p) = %d\n", i2400mu, ret);
+ return ret;
+}
+
+
+/*
+ * Tear down of the notification mechanism
+ *
+ * @i2400m: device descriptor
+ *
+ * Kill the interrupt endpoint urb, free any allocated resources.
+ *
+ * We need to check if we have done it before as for example,
+ * _suspend() call this; if after a suspend() we get a _disconnect()
+ * (as the case is when hibernating), nothing bad happens.
+ */
+void i2400mu_notification_release(struct i2400mu *i2400mu)
+{
+ struct device *dev = &i2400mu->usb_iface->dev;
+
+ d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);
+ if (i2400mu->notif_urb != NULL) {
+ usb_kill_urb(i2400mu->notif_urb);
+ kfree(i2400mu->notif_urb->transfer_buffer);
+ usb_free_urb(i2400mu->notif_urb);
+ i2400mu->notif_urb = NULL;
+ }
+ d_fnend(4, dev, "(i2400mu %p)\n", i2400mu);
+}
diff --git a/drivers/net/wimax/i2400m/usb-rx.c b/drivers/net/wimax/i2400m/usb-rx.c
new file mode 100644
index 000000000000..074cc1f89853
--- /dev/null
+++ b/drivers/net/wimax/i2400m/usb-rx.c
@@ -0,0 +1,417 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * USB RX handling
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ * - Initial implementation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * - Use skb_clone(), break up processing in chunks
+ * - Split transport/device specific
+ * - Make buffer size dynamic to exert less memory pressure
+ *
+ *
+ * This handles the RX path on USB.
+ *
+ * When a notification is received that says 'there is RX data ready',
+ * we call i2400mu_rx_kick(); that wakes up the RX kthread, which
+ * reads a buffer from USB and passes it to i2400m_rx() in the generic
+ * handling code. The RX buffer has an specific format that is
+ * described in rx.c.
+ *
+ * We use a kernel thread in a loop because:
+ *
+ * - we want to be able to call the USB power management get/put
+ * functions (blocking) before each transaction.
+ *
+ * - We might get a lot of notifications and we don't want to submit
+ * a zillion reads; by serializing, we are throttling.
+ *
+ * - RX data processing can get heavy enough so that it is not
+ * appropiate for doing it in the USB callback; thus we run it in a
+ * process context.
+ *
+ * We provide a read buffer of an arbitrary size (short of a page); if
+ * the callback reports -EOVERFLOW, it means it was too small, so we
+ * just double the size and retry (being careful to append, as
+ * sometimes the device provided some data). Every now and then we
+ * check if the average packet size is smaller than the current packet
+ * size and if so, we halve it. At the end, the size of the
+ * preallocated buffer should be following the average received
+ * transaction size, adapting dynamically to it.
+ *
+ * ROADMAP
+ *
+ * i2400mu_rx_kick() Called from notif.c when we get a
+ * 'data ready' notification
+ * i2400mu_rxd() Kernel RX daemon
+ * i2400mu_rx() Receive USB data
+ * i2400m_rx() Send data to generic i2400m RX handling
+ *
+ * i2400mu_rx_setup() called from i2400mu_bus_dev_start()
+ *
+ * i2400mu_rx_release() called from i2400mu_bus_dev_stop()
+ */
+#include <linux/workqueue.h>
+#include <linux/usb.h>
+#include "i2400m-usb.h"
+
+
+#define D_SUBMODULE rx
+#include "usb-debug-levels.h"
+
+/*
+ * Dynamic RX size
+ *
+ * We can't let the rx_size be a multiple of 512 bytes (the RX
+ * endpoint's max packet size). On some USB host controllers (we
+ * haven't been able to fully characterize which), if the device is
+ * about to send (for example) X bytes and we only post a buffer to
+ * receive n*512, it will fail to mark that as babble (so that
+ * i2400mu_rx() [case -EOVERFLOW] can resize the buffer and get the
+ * rest).
+ *
+ * So on growing or shrinking, if it is a multiple of the
+ * maxpacketsize, we remove some (instead of incresing some, so in a
+ * buddy allocator we try to waste less space).
+ *
+ * Note we also need a hook for this on i2400mu_rx() -- when we do the
+ * first read, we are sure we won't hit this spot because
+ * i240mm->rx_size has been set properly. However, if we have to
+ * double because of -EOVERFLOW, when we launch the read to get the
+ * rest of the data, we *have* to make sure that also is not a
+ * multiple of the max_pkt_size.
+ */
+
+static
+size_t i2400mu_rx_size_grow(struct i2400mu *i2400mu)
+{
+ struct device *dev = &i2400mu->usb_iface->dev;
+ size_t rx_size;
+ const size_t max_pkt_size = 512;
+
+ rx_size = 2 * i2400mu->rx_size;
+ if (rx_size % max_pkt_size == 0) {
+ rx_size -= 8;
+ d_printf(1, dev,
+ "RX: expected size grew to %zu [adjusted -8] "
+ "from %zu\n",
+ rx_size, i2400mu->rx_size);
+ } else
+ d_printf(1, dev,
+ "RX: expected size grew to %zu from %zu\n",
+ rx_size, i2400mu->rx_size);
+ return rx_size;
+}
+
+
+static
+void i2400mu_rx_size_maybe_shrink(struct i2400mu *i2400mu)
+{
+ const size_t max_pkt_size = 512;
+ struct device *dev = &i2400mu->usb_iface->dev;
+
+ if (unlikely(i2400mu->rx_size_cnt >= 100
+ && i2400mu->rx_size_auto_shrink)) {
+ size_t avg_rx_size =
+ i2400mu->rx_size_acc / i2400mu->rx_size_cnt;
+ size_t new_rx_size = i2400mu->rx_size / 2;
+ if (avg_rx_size < new_rx_size) {
+ if (new_rx_size % max_pkt_size == 0) {
+ new_rx_size -= 8;
+ d_printf(1, dev,
+ "RX: expected size shrank to %zu "
+ "[adjusted -8] from %zu\n",
+ new_rx_size, i2400mu->rx_size);
+ } else
+ d_printf(1, dev,
+ "RX: expected size shrank to %zu "
+ "from %zu\n",
+ new_rx_size, i2400mu->rx_size);
+ i2400mu->rx_size = new_rx_size;
+ i2400mu->rx_size_cnt = 0;
+ i2400mu->rx_size_acc = i2400mu->rx_size;
+ }
+ }
+}
+
+/*
+ * Receive a message with payloads from the USB bus into an skb
+ *
+ * @i2400mu: USB device descriptor
+ * @rx_skb: skb where to place the received message
+ *
+ * Deals with all the USB-specifics of receiving, dynamically
+ * increasing the buffer size if so needed. Returns the payload in the
+ * skb, ready to process. On a zero-length packet, we retry.
+ *
+ * On soft USB errors, we retry (until they become too frequent and
+ * then are promoted to hard); on hard USB errors, we reset the
+ * device. On other errors (skb realloacation, we just drop it and
+ * hope for the next invocation to solve it).
+ *
+ * Returns: pointer to the skb if ok, ERR_PTR on error.
+ * NOTE: this function might realloc the skb (if it is too small),
+ * so always update with the one returned.
+ * ERR_PTR() is < 0 on error.
+ */
+static
+struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb)
+{
+ int result = 0;
+ struct device *dev = &i2400mu->usb_iface->dev;
+ int usb_pipe, read_size, rx_size, do_autopm;
+ struct usb_endpoint_descriptor *epd;
+ const size_t max_pkt_size = 512;
+
+ d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);
+ do_autopm = atomic_read(&i2400mu->do_autopm);
+ result = do_autopm ?
+ usb_autopm_get_interface(i2400mu->usb_iface) : 0;
+ if (result < 0) {
+ dev_err(dev, "RX: can't get autopm: %d\n", result);
+ do_autopm = 0;
+ }
+ epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_BULK_IN);
+ usb_pipe = usb_rcvbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
+retry:
+ rx_size = skb_end_pointer(rx_skb) - rx_skb->data - rx_skb->len;
+ if (unlikely(rx_size % max_pkt_size == 0)) {
+ rx_size -= 8;
+ d_printf(1, dev, "RX: rx_size adapted to %d [-8]\n", rx_size);
+ }
+ result = usb_bulk_msg(
+ i2400mu->usb_dev, usb_pipe, rx_skb->data + rx_skb->len,
+ rx_size, &read_size, HZ);
+ usb_mark_last_busy(i2400mu->usb_dev);
+ switch (result) {
+ case 0:
+ if (read_size == 0)
+ goto retry; /* ZLP, just resubmit */
+ skb_put(rx_skb, read_size);
+ break;
+ case -EINVAL: /* while removing driver */
+ case -ENODEV: /* dev disconnect ... */
+ case -ENOENT: /* just ignore it */
+ case -ESHUTDOWN:
+ case -ECONNRESET:
+ break;
+ case -EOVERFLOW: { /* too small, reallocate */
+ struct sk_buff *new_skb;
+ rx_size = i2400mu_rx_size_grow(i2400mu);
+ if (rx_size <= (1 << 16)) /* cap it */
+ i2400mu->rx_size = rx_size;
+ else if (printk_ratelimit()) {
+ dev_err(dev, "BUG? rx_size up to %d\n", rx_size);
+ result = -EINVAL;
+ goto out;
+ }
+ skb_put(rx_skb, read_size);
+ new_skb = skb_copy_expand(rx_skb, 0, rx_size - rx_skb->len,
+ GFP_KERNEL);
+ if (new_skb == NULL) {
+ if (printk_ratelimit())
+ dev_err(dev, "RX: Can't reallocate skb to %d; "
+ "RX dropped\n", rx_size);
+ kfree(rx_skb);
+ result = 0;
+ goto out; /* drop it...*/
+ }
+ kfree_skb(rx_skb);
+ rx_skb = new_skb;
+ i2400mu->rx_size_cnt = 0;
+ i2400mu->rx_size_acc = i2400mu->rx_size;
+ d_printf(1, dev, "RX: size changed to %d, received %d, "
+ "copied %d, capacity %ld\n",
+ rx_size, read_size, rx_skb->len,
+ (long) (skb_end_pointer(new_skb) - new_skb->head));
+ goto retry;
+ }
+ /* In most cases, it happens due to the hardware scheduling a
+ * read when there was no data - unfortunately, we have no way
+ * to tell this timeout from a USB timeout. So we just ignore
+ * it. */
+ case -ETIMEDOUT:
+ dev_err(dev, "RX: timeout: %d\n", result);
+ result = 0;
+ break;
+ default: /* Any error */
+ if (edc_inc(&i2400mu->urb_edc,
+ EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME))
+ goto error_reset;
+ dev_err(dev, "RX: error receiving URB: %d, retrying\n", result);
+ goto retry;
+ }
+out:
+ if (do_autopm)
+ usb_autopm_put_interface(i2400mu->usb_iface);
+ d_fnend(4, dev, "(i2400mu %p) = %p\n", i2400mu, rx_skb);
+ return rx_skb;
+
+error_reset:
+ dev_err(dev, "RX: maximum errors in URB exceeded; "
+ "resetting device\n");
+ usb_queue_reset_device(i2400mu->usb_iface);
+ rx_skb = ERR_PTR(result);
+ goto out;
+}
+
+
+/*
+ * Kernel thread for USB reception of data
+ *
+ * This thread waits for a kick; once kicked, it will allocate an skb
+ * and receive a single message to it from USB (using
+ * i2400mu_rx()). Once received, it is passed to the generic i2400m RX
+ * code for processing.
+ *
+ * When done processing, it runs some dirty statistics to verify if
+ * the last 100 messages received were smaller than half of the
+ * current RX buffer size. In that case, the RX buffer size is
+ * halved. This will helps lowering the pressure on the memory
+ * allocator.
+ *
+ * Hard errors force the thread to exit.
+ */
+static
+int i2400mu_rxd(void *_i2400mu)
+{
+ int result = 0;
+ struct i2400mu *i2400mu = _i2400mu;
+ struct i2400m *i2400m = &i2400mu->i2400m;
+ struct device *dev = &i2400mu->usb_iface->dev;
+ struct net_device *net_dev = i2400m->wimax_dev.net_dev;
+ size_t pending;
+ int rx_size;
+ struct sk_buff *rx_skb;
+
+ d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);
+ while (1) {
+ d_printf(2, dev, "TX: waiting for messages\n");
+ pending = 0;
+ wait_event_interruptible(
+ i2400mu->rx_wq,
+ (kthread_should_stop() /* check this first! */
+ || (pending = atomic_read(&i2400mu->rx_pending_count)))
+ );
+ if (kthread_should_stop())
+ break;
+ if (pending == 0)
+ continue;
+ rx_size = i2400mu->rx_size;
+ d_printf(2, dev, "RX: reading up to %d bytes\n", rx_size);
+ rx_skb = __netdev_alloc_skb(net_dev, rx_size, GFP_KERNEL);
+ if (rx_skb == NULL) {
+ dev_err(dev, "RX: can't allocate skb [%d bytes]\n",
+ rx_size);
+ msleep(50); /* give it some time? */
+ continue;
+ }
+
+ /* Receive the message with the payloads */
+ rx_skb = i2400mu_rx(i2400mu, rx_skb);
+ result = PTR_ERR(rx_skb);
+ if (IS_ERR(rx_skb))
+ goto out;
+ atomic_dec(&i2400mu->rx_pending_count);
+ if (rx_skb->len == 0) { /* some ignorable condition */
+ kfree_skb(rx_skb);
+ continue;
+ }
+
+ /* Deliver the message to the generic i2400m code */
+ i2400mu->rx_size_cnt++;
+ i2400mu->rx_size_acc += rx_skb->len;
+ result = i2400m_rx(i2400m, rx_skb);
+ if (result == -EIO
+ && edc_inc(&i2400mu->urb_edc,
+ EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+ goto error_reset;
+ }
+
+ /* Maybe adjust RX buffer size */
+ i2400mu_rx_size_maybe_shrink(i2400mu);
+ }
+ result = 0;
+out:
+ d_fnend(4, dev, "(i2400mu %p) = %d\n", i2400mu, result);
+ return result;
+
+error_reset:
+ dev_err(dev, "RX: maximum errors in received buffer exceeded; "
+ "resetting device\n");
+ usb_queue_reset_device(i2400mu->usb_iface);
+ goto out;
+}
+
+
+/*
+ * Start reading from the device
+ *
+ * @i2400m: device instance
+ *
+ * Notify the RX thread that there is data pending.
+ */
+void i2400mu_rx_kick(struct i2400mu *i2400mu)
+{
+ struct i2400m *i2400m = &i2400mu->i2400m;
+ struct device *dev = &i2400mu->usb_iface->dev;
+
+ d_fnstart(3, dev, "(i2400mu %p)\n", i2400m);
+ atomic_inc(&i2400mu->rx_pending_count);
+ wake_up_all(&i2400mu->rx_wq);
+ d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
+}
+
+
+int i2400mu_rx_setup(struct i2400mu *i2400mu)
+{
+ int result = 0;
+ struct i2400m *i2400m = &i2400mu->i2400m;
+ struct device *dev = &i2400mu->usb_iface->dev;
+ struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
+
+ i2400mu->rx_kthread = kthread_run(i2400mu_rxd, i2400mu, "%s-rx",
+ wimax_dev->name);
+ if (IS_ERR(i2400mu->rx_kthread)) {
+ result = PTR_ERR(i2400mu->rx_kthread);
+ dev_err(dev, "RX: cannot start thread: %d\n", result);
+ }
+ return result;
+}
+
+void i2400mu_rx_release(struct i2400mu *i2400mu)
+{
+ kthread_stop(i2400mu->rx_kthread);
+}
+
diff --git a/drivers/net/wimax/i2400m/usb-tx.c b/drivers/net/wimax/i2400m/usb-tx.c
new file mode 100644
index 000000000000..dfd893356f49
--- /dev/null
+++ b/drivers/net/wimax/i2400m/usb-tx.c
@@ -0,0 +1,229 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * USB specific TX handling
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. 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 of 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.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ * - Initial implementation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * - Split transport/device specific
+ *
+ *
+ * Takes the TX messages in the i2400m's driver TX FIFO and sends them
+ * to the device until there are no more.
+ *
+ * If we fail sending the message, we just drop it. There isn't much
+ * we can do at this point. We could also retry, but the USB stack has
+ * already retried and still failed, so there is not much of a
+ * point. As well, most of the traffic is network, which has recovery
+ * methods for dropped packets.
+ *
+ * For sending we just obtain a FIFO buffer to send, send it to the
+ * USB bulk out, tell the TX FIFO code we have sent it; query for
+ * another one, etc... until done.
+ *
+ * We use a thread so we can call usb_autopm_enable() and
+ * usb_autopm_disable() for each transaction; this way when the device
+ * goes idle, it will suspend. It also has less overhead than a
+ * dedicated workqueue, as it is being used for a single task.
+ *
+ * ROADMAP
+ *
+ * i2400mu_tx_setup()
+ * i2400mu_tx_release()
+ *
+ * i2400mu_bus_tx_kick() - Called by the tx.c code when there
+ * is new data in the FIFO.
+ * i2400mu_txd()
+ * i2400m_tx_msg_get()
+ * i2400m_tx_msg_sent()
+ */
+#include "i2400m-usb.h"
+
+
+#define D_SUBMODULE tx
+#include "usb-debug-levels.h"
+
+
+/*
+ * Get the next TX message in the TX FIFO and send it to the device
+ *
+ * Note that any iteration consumes a message to be sent, no matter if
+ * it succeeds or fails (we have no real way to retry or complain).
+ *
+ * Return: 0 if ok, < 0 errno code on hard error.
+ */
+static
+int i2400mu_tx(struct i2400mu *i2400mu, struct i2400m_msg_hdr *tx_msg,
+ size_t tx_msg_size)
+{
+ int result = 0;
+ struct i2400m *i2400m = &i2400mu->i2400m;
+ struct device *dev = &i2400mu->usb_iface->dev;
+ int usb_pipe, sent_size, do_autopm;
+ struct usb_endpoint_descriptor *epd;
+
+ d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);
+ do_autopm = atomic_read(&i2400mu->do_autopm);
+ result = do_autopm ?
+ usb_autopm_get_interface(i2400mu->usb_iface) : 0;
+ if (result < 0) {
+ dev_err(dev, "TX: can't get autopm: %d\n", result);
+ do_autopm = 0;
+ }
+ epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_BULK_OUT);
+ usb_pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
+retry:
+ result = usb_bulk_msg(i2400mu->usb_dev, usb_pipe,
+ tx_msg, tx_msg_size, &sent_size, HZ);
+ usb_mark_last_busy(i2400mu->usb_dev);
+ switch (result) {
+ case 0:
+ if (sent_size != tx_msg_size) { /* Too short? drop it */
+ dev_err(dev, "TX: short write (%d B vs %zu "
+ "expected)\n", sent_size, tx_msg_size);
+ result = -EIO;
+ }
+ break;
+ case -EINVAL: /* while removing driver */
+ case -ENODEV: /* dev disconnect ... */
+ case -ENOENT: /* just ignore it */
+ case -ESHUTDOWN: /* and exit */
+ case -ECONNRESET:
+ result = -ESHUTDOWN;
+ break;
+ default: /* Some error? */
+ if (edc_inc(&i2400mu->urb_edc,
+ EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "TX: maximum errors in URB "
+ "exceeded; resetting device\n");
+ usb_queue_reset_device(i2400mu->usb_iface);
+ } else {
+ dev_err(dev, "TX: cannot send URB; retrying. "
+ "tx_msg @%zu %zu B [%d sent]: %d\n",
+ (void *) tx_msg - i2400m->tx_buf,
+ tx_msg_size, sent_size, result);
+ goto retry;
+ }
+ }
+ if (do_autopm)
+ usb_autopm_put_interface(i2400mu->usb_iface);
+ d_fnend(4, dev, "(i2400mu %p) = result\n", i2400mu);
+ return result;
+}
+
+
+/*
+ * Get the next TX message in the TX FIFO and send it to the device
+ *
+ * Note we exit the loop if i2400mu_tx() fails; that funtion only
+ * fails on hard error (failing to tx a buffer not being one of them,
+ * see its doc).
+ *
+ * Return: 0
+ */
+static
+int i2400mu_txd(void *_i2400mu)
+{
+ int result = 0;
+ struct i2400mu *i2400mu = _i2400mu;
+ struct i2400m *i2400m = &i2400mu->i2400m;
+ struct device *dev = &i2400mu->usb_iface->dev;
+ struct i2400m_msg_hdr *tx_msg;
+ size_t tx_msg_size;
+
+ d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);
+
+ while (1) {
+ d_printf(2, dev, "TX: waiting for messages\n");
+ tx_msg = NULL;
+ wait_event_interruptible(
+ i2400mu->tx_wq,
+ (kthread_should_stop() /* check this first! */
+ || (tx_msg = i2400m_tx_msg_get(i2400m, &tx_msg_size)))
+ );
+ if (kthread_should_stop())
+ break;
+ WARN_ON(tx_msg == NULL); /* should not happen...*/
+ d_printf(2, dev, "TX: submitting %zu bytes\n", tx_msg_size);
+ d_dump(5, dev, tx_msg, tx_msg_size);
+ /* Yeah, we ignore errors ... not much we can do */
+ i2400mu_tx(i2400mu, tx_msg, tx_msg_size);
+ i2400m_tx_msg_sent(i2400m); /* ack it, advance the FIFO */
+ if (result < 0)
+ break;
+ }
+ d_fnend(4, dev, "(i2400mu %p) = %d\n", i2400mu, result);
+ return result;
+}
+
+
+/*
+ * i2400m TX engine notifies us that there is data in the FIFO ready
+ * for TX
+ *
+ * If there is a URB in flight, don't do anything; when it finishes,
+ * it will see there is data in the FIFO and send it. Else, just
+ * submit a write.
+ */
+void i2400mu_bus_tx_kick(struct i2400m *i2400m)
+{
+ struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
+ struct device *dev = &i2400mu->usb_iface->dev;
+
+ d_fnstart(3, dev, "(i2400m %p) = void\n", i2400m);
+ wake_up_all(&i2400mu->tx_wq);
+ d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
+}
+
+
+int i2400mu_tx_setup(struct i2400mu *i2400mu)
+{
+ int result = 0;
+ struct i2400m *i2400m = &i2400mu->i2400m;
+ struct device *dev = &i2400mu->usb_iface->dev;
+ struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
+
+ i2400mu->tx_kthread = kthread_run(i2400mu_txd, i2400mu, "%s-tx",
+ wimax_dev->name);
+ if (IS_ERR(i2400mu->tx_kthread)) {
+ result = PTR_ERR(i2400mu->tx_kthread);
+ dev_err(dev, "TX: cannot start thread: %d\n", result);
+ }
+ return result;
+}
+
+void i2400mu_tx_release(struct i2400mu *i2400mu)
+{
+ kthread_stop(i2400mu->tx_kthread);
+}
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
new file mode 100644
index 000000000000..c6d93465c7e2
--- /dev/null
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -0,0 +1,597 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Linux driver model glue for USB device, reset & fw upload
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This 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.
+ *
+ *
+ * See i2400m-usb.h for a general description of this driver.
+ *
+ * This file implements driver model glue, and hook ups for the
+ * generic driver to implement the bus-specific functions (device
+ * communication setup/tear down, firmware upload and resetting).
+ *
+ * ROADMAP
+ *
+ * i2400mu_probe()
+ * alloc_netdev()...
+ * i2400mu_netdev_setup()
+ * i2400mu_init()
+ * i2400m_netdev_setup()
+ * i2400m_setup()...
+ *
+ * i2400mu_disconnect
+ * i2400m_release()
+ * free_netdev()
+ *
+ * i2400mu_suspend()
+ * i2400m_cmd_enter_powersave()
+ * i2400mu_notification_release()
+ *
+ * i2400mu_resume()
+ * i2400mu_notification_setup()
+ *
+ * i2400mu_bus_dev_start() Called by i2400m_dev_start() [who is
+ * i2400mu_tx_setup() called by i2400m_setup()]
+ * i2400mu_rx_setup()
+ * i2400mu_notification_setup()
+ *
+ * i2400mu_bus_dev_stop() Called by i2400m_dev_stop() [who is
+ * i2400mu_notification_release() called by i2400m_release()]
+ * i2400mu_rx_release()
+ * i2400mu_tx_release()
+ *
+ * i2400mu_bus_reset() Called by i2400m->bus_reset
+ * __i2400mu_reset()
+ * __i2400mu_send_barker()
+ * usb_reset_device()
+ */
+#include "i2400m-usb.h"
+#include <linux/wimax/i2400m.h>
+#include <linux/debugfs.h>
+
+
+#define D_SUBMODULE usb
+#include "usb-debug-levels.h"
+
+
+/* Our firmware file name */
+#define I2400MU_FW_FILE_NAME "i2400m-fw-usb-" I2400M_FW_VERSION ".sbcf"
+
+static
+int i2400mu_bus_dev_start(struct i2400m *i2400m)
+{
+ int result;
+ struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
+ struct device *dev = &i2400mu->usb_iface->dev;
+
+ d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+ result = i2400mu_tx_setup(i2400mu);
+ if (result < 0)
+ goto error_usb_tx_setup;
+ result = i2400mu_rx_setup(i2400mu);
+ if (result < 0)
+ goto error_usb_rx_setup;
+ result = i2400mu_notification_setup(i2400mu);
+ if (result < 0)
+ goto error_notif_setup;
+ d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
+ return result;
+
+error_notif_setup:
+ i2400mu_rx_release(i2400mu);
+error_usb_rx_setup:
+ i2400mu_tx_release(i2400mu);
+error_usb_tx_setup:
+ d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
+ return result;
+}
+
+
+static
+void i2400mu_bus_dev_stop(struct i2400m *i2400m)
+{
+ struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
+ struct device *dev = &i2400mu->usb_iface->dev;
+
+ d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+ i2400mu_notification_release(i2400mu);
+ i2400mu_rx_release(i2400mu);
+ i2400mu_tx_release(i2400mu);
+ d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
+}
+
+
+/*
+ * Sends a barker buffer to the device
+ *
+ * This helper will allocate a kmalloced buffer and use it to transmit
+ * (then free it). Reason for this is that other arches cannot use
+ * stack/vmalloc/text areas for DMA transfers.
+ *
+ * Error recovery here is simpler: anything is considered a hard error
+ * and will move the reset code to use a last-resort bus-based reset.
+ */
+static
+int __i2400mu_send_barker(struct i2400mu *i2400mu,
+ const __le32 *barker,
+ size_t barker_size,
+ unsigned endpoint)
+{
+ struct usb_endpoint_descriptor *epd = NULL;
+ int pipe, actual_len, ret;
+ struct device *dev = &i2400mu->usb_iface->dev;
+ void *buffer;
+ int do_autopm = 1;
+
+ ret = usb_autopm_get_interface(i2400mu->usb_iface);
+ if (ret < 0) {
+ dev_err(dev, "RESET: can't get autopm: %d\n", ret);
+ do_autopm = 0;
+ }
+ ret = -ENOMEM;
+ buffer = kmalloc(barker_size, GFP_KERNEL);
+ if (buffer == NULL)
+ goto error_kzalloc;
+ epd = usb_get_epd(i2400mu->usb_iface, endpoint);
+ pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
+ memcpy(buffer, barker, barker_size);
+ ret = usb_bulk_msg(i2400mu->usb_dev, pipe, buffer, barker_size,
+ &actual_len, HZ);
+ if (ret < 0) {
+ if (ret != -EINVAL)
+ dev_err(dev, "E: barker error: %d\n", ret);
+ } else if (actual_len != barker_size) {
+ dev_err(dev, "E: only %d bytes transmitted\n", actual_len);
+ ret = -EIO;
+ }
+ kfree(buffer);
+error_kzalloc:
+ if (do_autopm)
+ usb_autopm_put_interface(i2400mu->usb_iface);
+ return ret;
+}
+
+
+/*
+ * Reset a device at different levels (warm, cold or bus)
+ *
+ * @i2400m: device descriptor
+ * @reset_type: soft, warm or bus reset (I2400M_RT_WARM/SOFT/BUS)
+ *
+ * Warm and cold resets get a USB reset if they fail.
+ *
+ * Warm reset:
+ *
+ * The device will be fully reset internally, but won't be
+ * disconnected from the USB bus (so no reenumeration will
+ * happen). Firmware upload will be neccessary.
+ *
+ * The device will send a reboot barker in the notification endpoint
+ * that will trigger the driver to reinitialize the state
+ * automatically from notif.c:i2400m_notification_grok() into
+ * i2400m_dev_bootstrap_delayed().
+ *
+ * Cold and bus (USB) reset:
+ *
+ * The device will be fully reset internally, disconnected from the
+ * USB bus an a reenumeration will happen. Firmware upload will be
+ * neccessary. Thus, we don't do any locking or struct
+ * reinitialization, as we are going to be fully disconnected and
+ * reenumerated.
+ *
+ * Note we need to return -ENODEV if a warm reset was requested and we
+ * had to resort to a bus reset. See i2400m_op_reset(), wimax_reset()
+ * and wimax_dev->op_reset.
+ *
+ * WARNING: no driver state saved/fixed
+ */
+static
+int i2400mu_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
+{
+ int result;
+ struct i2400mu *i2400mu =
+ container_of(i2400m, struct i2400mu, i2400m);
+ struct device *dev = i2400m_dev(i2400m);
+ static const __le32 i2400m_WARM_BOOT_BARKER[4] = {
+ __constant_cpu_to_le32(I2400M_WARM_RESET_BARKER),
+ __constant_cpu_to_le32(I2400M_WARM_RESET_BARKER),
+ __constant_cpu_to_le32(I2400M_WARM_RESET_BARKER),
+ __constant_cpu_to_le32(I2400M_WARM_RESET_BARKER),
+ };
+ static const __le32 i2400m_COLD_BOOT_BARKER[4] = {
+ __constant_cpu_to_le32(I2400M_COLD_RESET_BARKER),
+ __constant_cpu_to_le32(I2400M_COLD_RESET_BARKER),
+ __constant_cpu_to_le32(I2400M_COLD_RESET_BARKER),
+ __constant_cpu_to_le32(I2400M_COLD_RESET_BARKER),
+ };
+
+ d_fnstart(3, dev, "(i2400m %p rt %u)\n", i2400m, rt);
+ if (rt == I2400M_RT_WARM)
+ result = __i2400mu_send_barker(i2400mu, i2400m_WARM_BOOT_BARKER,
+ sizeof(i2400m_WARM_BOOT_BARKER),
+ I2400MU_EP_BULK_OUT);
+ else if (rt == I2400M_RT_COLD)
+ result = __i2400mu_send_barker(i2400mu, i2400m_COLD_BOOT_BARKER,
+ sizeof(i2400m_COLD_BOOT_BARKER),
+ I2400MU_EP_RESET_COLD);
+ else if (rt == I2400M_RT_BUS) {
+do_bus_reset:
+ result = usb_reset_device(i2400mu->usb_dev);
+ switch (result) {
+ case 0:
+ case -EINVAL: /* device is gone */
+ case -ENODEV:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ result = rt == I2400M_RT_WARM ? -ENODEV : 0;
+ break; /* We assume the device is disconnected */
+ default:
+ dev_err(dev, "USB reset failed (%d), giving up!\n",
+ result);
+ }
+ } else
+ BUG();
+ if (result < 0
+ && result != -EINVAL /* device is gone */
+ && rt != I2400M_RT_BUS) {
+ dev_err(dev, "%s reset failed (%d); trying USB reset\n",
+ rt == I2400M_RT_WARM ? "warm" : "cold", result);
+ rt = I2400M_RT_BUS;
+ goto do_bus_reset;
+ }
+ d_fnend(3, dev, "(i2400m %p rt %u) = %d\n", i2400m, rt, result);
+ return result;
+}
+
+
+static
+void i2400mu_netdev_setup(struct net_device *net_dev)
+{
+ struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
+ struct i2400mu *i2400mu = container_of(i2400m, struct i2400mu, i2400m);
+ i2400mu_init(i2400mu);
+ i2400m_netdev_setup(net_dev);
+}
+
+
+/*
+ * Debug levels control; see debug.h
+ */
+struct d_level D_LEVEL[] = {
+ D_SUBMODULE_DEFINE(usb),
+ D_SUBMODULE_DEFINE(fw),
+ D_SUBMODULE_DEFINE(notif),
+ D_SUBMODULE_DEFINE(rx),
+ D_SUBMODULE_DEFINE(tx),
+};
+size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
+
+
+#define __debugfs_register(prefix, name, parent) \
+do { \
+ result = d_level_register_debugfs(prefix, name, parent); \
+ if (result < 0) \
+ goto error; \
+} while (0)
+
+
+static
+int i2400mu_debugfs_add(struct i2400mu *i2400mu)
+{
+ int result;
+ struct device *dev = &i2400mu->usb_iface->dev;
+ struct dentry *dentry = i2400mu->i2400m.wimax_dev.debugfs_dentry;
+ struct dentry *fd;
+
+ dentry = debugfs_create_dir("i2400m-usb", dentry);
+ result = PTR_ERR(dentry);
+ if (IS_ERR(dentry)) {
+ if (result == -ENODEV)
+ result = 0; /* No debugfs support */
+ goto error;
+ }
+ i2400mu->debugfs_dentry = dentry;
+ __debugfs_register("dl_", usb, dentry);
+ __debugfs_register("dl_", fw, dentry);
+ __debugfs_register("dl_", notif, dentry);
+ __debugfs_register("dl_", rx, dentry);
+ __debugfs_register("dl_", tx, dentry);
+
+ /* Don't touch these if you don't know what you are doing */
+ fd = debugfs_create_u8("rx_size_auto_shrink", 0600, dentry,
+ &i2400mu->rx_size_auto_shrink);
+ result = PTR_ERR(fd);
+ if (IS_ERR(fd) && result != -ENODEV) {
+ dev_err(dev, "Can't create debugfs entry "
+ "rx_size_auto_shrink: %d\n", result);
+ goto error;
+ }
+
+ fd = debugfs_create_size_t("rx_size", 0600, dentry,
+ &i2400mu->rx_size);
+ result = PTR_ERR(fd);
+ if (IS_ERR(fd) && result != -ENODEV) {
+ dev_err(dev, "Can't create debugfs entry "
+ "rx_size: %d\n", result);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ debugfs_remove_recursive(i2400mu->debugfs_dentry);
+ return result;
+}
+
+
+/*
+ * Probe a i2400m interface and register it
+ *
+ * @iface: USB interface to link to
+ * @id: USB class/subclass/protocol id
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * Alloc a net device, initialize the bus-specific details and then
+ * calls the bus-generic initialization routine. That will register
+ * the wimax and netdev devices, upload the firmware [using
+ * _bus_bm_*()], call _bus_dev_start() to finalize the setup of the
+ * communication with the device and then will start to talk to it to
+ * finnish setting it up.
+ */
+static
+int i2400mu_probe(struct usb_interface *iface,
+ const struct usb_device_id *id)
+{
+ int result;
+ struct net_device *net_dev;
+ struct device *dev = &iface->dev;
+ struct i2400m *i2400m;
+ struct i2400mu *i2400mu;
+ struct usb_device *usb_dev = interface_to_usbdev(iface);
+
+ if (usb_dev->speed != USB_SPEED_HIGH)
+ dev_err(dev, "device not connected as high speed\n");
+
+ /* Allocate instance [calls i2400m_netdev_setup() on it]. */
+ result = -ENOMEM;
+ net_dev = alloc_netdev(sizeof(*i2400mu), "wmx%d",
+ i2400mu_netdev_setup);
+ if (net_dev == NULL) {
+ dev_err(dev, "no memory for network device instance\n");
+ goto error_alloc_netdev;
+ }
+ SET_NETDEV_DEV(net_dev, dev);
+ i2400m = net_dev_to_i2400m(net_dev);
+ i2400mu = container_of(i2400m, struct i2400mu, i2400m);
+ i2400m->wimax_dev.net_dev = net_dev;
+ i2400mu->usb_dev = usb_get_dev(usb_dev);
+ i2400mu->usb_iface = iface;
+ usb_set_intfdata(iface, i2400mu);
+
+ i2400m->bus_tx_block_size = I2400MU_BLK_SIZE;
+ i2400m->bus_pl_size_max = I2400MU_PL_SIZE_MAX;
+ i2400m->bus_dev_start = i2400mu_bus_dev_start;
+ i2400m->bus_dev_stop = i2400mu_bus_dev_stop;
+ i2400m->bus_tx_kick = i2400mu_bus_tx_kick;
+ i2400m->bus_reset = i2400mu_bus_reset;
+ i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send;
+ i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack;
+ i2400m->bus_fw_name = I2400MU_FW_FILE_NAME;
+ i2400m->bus_bm_mac_addr_impaired = 0;
+
+#ifdef CONFIG_PM
+ iface->needs_remote_wakeup = 1; /* autosuspend (15s delay) */
+ device_init_wakeup(dev, 1);
+ usb_autopm_enable(i2400mu->usb_iface);
+ usb_dev->autosuspend_delay = 15 * HZ;
+ usb_dev->autosuspend_disabled = 0;
+#endif
+
+ result = i2400m_setup(i2400m, I2400M_BRI_MAC_REINIT);
+ if (result < 0) {
+ dev_err(dev, "cannot setup device: %d\n", result);
+ goto error_setup;
+ }
+ result = i2400mu_debugfs_add(i2400mu);
+ if (result < 0) {
+ dev_err(dev, "Can't register i2400mu's debugfs: %d\n", result);
+ goto error_debugfs_add;
+ }
+ return 0;
+
+error_debugfs_add:
+ i2400m_release(i2400m);
+error_setup:
+ usb_set_intfdata(iface, NULL);
+ usb_put_dev(i2400mu->usb_dev);
+ free_netdev(net_dev);
+error_alloc_netdev:
+ return result;
+}
+
+
+/*
+ * Disconect a i2400m from the system.
+ *
+ * i2400m_stop() has been called before, so al the rx and tx contexts
+ * have been taken down already. Make sure the queue is stopped,
+ * unregister netdev and i2400m, free and kill.
+ */
+static
+void i2400mu_disconnect(struct usb_interface *iface)
+{
+ struct i2400mu *i2400mu = usb_get_intfdata(iface);
+ struct i2400m *i2400m = &i2400mu->i2400m;
+ struct net_device *net_dev = i2400m->wimax_dev.net_dev;
+ struct device *dev = &iface->dev;
+
+ d_fnstart(3, dev, "(iface %p i2400m %p)\n", iface, i2400m);
+
+ debugfs_remove_recursive(i2400mu->debugfs_dentry);
+ i2400m_release(i2400m);
+ usb_set_intfdata(iface, NULL);
+ usb_put_dev(i2400mu->usb_dev);
+ free_netdev(net_dev);
+ d_fnend(3, dev, "(iface %p i2400m %p) = void\n", iface, i2400m);
+}
+
+
+/*
+ * Get the device ready for USB port or system standby and hibernation
+ *
+ * USB port and system standby are handled the same.
+ *
+ * When the system hibernates, the USB device is powered down and then
+ * up, so we don't really have to do much here, as it will be seen as
+ * a reconnect. Still for simplicity we consider this case the same as
+ * suspend, so that the device has a chance to do notify the base
+ * station (if connected).
+ *
+ * So at the end, the three cases require common handling.
+ *
+ * If at the time of this call the device's firmware is not loaded,
+ * nothing has to be done.
+ *
+ * If the firmware is loaded, we need to:
+ *
+ * - tell the device to go into host interface power save mode, wait
+ * for it to ack
+ *
+ * This is quite more interesting than it is; we need to execute a
+ * command, but this time, we don't want the code in usb-{tx,rx}.c
+ * to call the usb_autopm_get/put_interface() barriers as it'd
+ * deadlock, so we need to decrement i2400mu->do_autopm, that acts
+ * as a poor man's semaphore. Ugly, but it works.
+ *
+ * As well, the device might refuse going to sleep for whichever
+ * reason. In this case we just fail. For system suspend/hibernate,
+ * we *can't* fail. We look at usb_dev->auto_pm to see if the
+ * suspend call comes from the USB stack or from the system and act
+ * in consequence.
+ *
+ * - stop the notification endpoint polling
+ */
+static
+int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg)
+{
+ int result = 0;
+ struct device *dev = &iface->dev;
+ struct i2400mu *i2400mu = usb_get_intfdata(iface);
+#ifdef CONFIG_PM
+ struct usb_device *usb_dev = i2400mu->usb_dev;
+#endif
+ struct i2400m *i2400m = &i2400mu->i2400m;
+
+ d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event);
+ if (i2400m->updown == 0)
+ goto no_firmware;
+ d_printf(1, dev, "fw up, requesting standby\n");
+ atomic_dec(&i2400mu->do_autopm);
+ result = i2400m_cmd_enter_powersave(i2400m);
+ atomic_inc(&i2400mu->do_autopm);
+#ifdef CONFIG_PM
+ if (result < 0 && usb_dev->auto_pm == 0) {
+ /* System suspend, can't fail */
+ dev_err(dev, "failed to suspend, will reset on resume\n");
+ result = 0;
+ }
+#endif
+ if (result < 0)
+ goto error_enter_powersave;
+ i2400mu_notification_release(i2400mu);
+ d_printf(1, dev, "fw up, got standby\n");
+error_enter_powersave:
+no_firmware:
+ d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n",
+ iface, pm_msg.event, result);
+ return result;
+}
+
+
+static
+int i2400mu_resume(struct usb_interface *iface)
+{
+ int ret = 0;
+ struct device *dev = &iface->dev;
+ struct i2400mu *i2400mu = usb_get_intfdata(iface);
+ struct i2400m *i2400m = &i2400mu->i2400m;
+
+ d_fnstart(3, dev, "(iface %p)\n", iface);
+ if (i2400m->updown == 0) {
+ d_printf(1, dev, "fw was down, no resume neeed\n");
+ goto out;
+ }
+ d_printf(1, dev, "fw was up, resuming\n");
+ i2400mu_notification_setup(i2400mu);
+ /* USB has flow control, so we don't need to give it time to
+ * come back; otherwise, we'd use something like a get-state
+ * command... */
+out:
+ d_fnend(3, dev, "(iface %p) = %d\n", iface, ret);
+ return ret;
+}
+
+
+static
+struct usb_device_id i2400mu_id_table[] = {
+ { USB_DEVICE(0x8086, 0x0181) },
+ { USB_DEVICE(0x8086, 0x1403) },
+ { USB_DEVICE(0x8086, 0x1405) },
+ { USB_DEVICE(0x8086, 0x0180) },
+ { USB_DEVICE(0x8086, 0x0182) },
+ { USB_DEVICE(0x8086, 0x1406) },
+ { USB_DEVICE(0x8086, 0x1403) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, i2400mu_id_table);
+
+
+static
+struct usb_driver i2400mu_driver = {
+ .name = KBUILD_MODNAME,
+ .suspend = i2400mu_suspend,
+ .resume = i2400mu_resume,
+ .probe = i2400mu_probe,
+ .disconnect = i2400mu_disconnect,
+ .id_table = i2400mu_id_table,
+ .supports_autosuspend = 1,
+};
+
+static
+int __init i2400mu_driver_init(void)
+{
+ return usb_register(&i2400mu_driver);
+}
+module_init(i2400mu_driver_init);
+
+
+static
+void __exit i2400mu_driver_exit(void)
+{
+ flush_scheduled_work(); /* for the stuff we schedule from sysfs.c */
+ usb_deregister(&i2400mu_driver);
+}
+module_exit(i2400mu_driver_exit);
+
+MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
+MODULE_DESCRIPTION("Intel 2400M WiMAX networking for USB");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(I2400MU_FW_FILE_NAME);
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index ea543fcf2687..e4f9f747de88 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -111,7 +111,7 @@ config WLAN_80211
lets you choose drivers.
config PCMCIA_RAYCS
- tristate "Aviator/Raytheon 2.4MHz wireless support"
+ tristate "Aviator/Raytheon 2.4GHz wireless support"
depends on PCMCIA && WLAN_80211
select WIRELESS_EXT
---help---
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index 4af2607deec0..8ef87356e083 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -2644,7 +2644,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
if (skb_headroom(skb) < padsize) {
ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough"
" headroom to pad %d\n", hdrlen, padsize);
- return -1;
+ return NETDEV_TX_BUSY;
}
skb_push(skb, padsize);
memmove(skb->data, skb->data+padsize, hdrlen);
@@ -2655,7 +2655,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
ATH5K_ERR(sc, "no further txbuf available, dropping packet\n");
spin_unlock_irqrestore(&sc->txbuflock, flags);
ieee80211_stop_queue(hw, skb_get_queue_mapping(skb));
- return -1;
+ return NETDEV_TX_BUSY;
}
bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list);
list_del(&bf->list);
@@ -2673,10 +2673,10 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
sc->txbuf_len++;
spin_unlock_irqrestore(&sc->txbuflock, flags);
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
- return 0;
+ return NETDEV_TX_OK;
}
static int
diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c
index 7e2b1a67e5da..b65b4feb2d28 100644
--- a/drivers/net/wireless/ath5k/dma.c
+++ b/drivers/net/wireless/ath5k/dma.c
@@ -594,7 +594,7 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
* 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.
+ * after a successful assoc + some jiffies.
interrupt_mask &= ~AR5K_INT_BMISS;
*/
}
diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c
index 0cac05c6a9ce..75eb9f43c741 100644
--- a/drivers/net/wireless/ath5k/pcu.c
+++ b/drivers/net/wireless/ath5k/pcu.c
@@ -65,7 +65,7 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah)
if (ah->ah_version == AR5K_AR5210)
pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
else
- AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC);
+ AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
break;
case NL80211_IFTYPE_AP:
@@ -75,7 +75,7 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah)
if (ah->ah_version == AR5K_AR5210)
pcu_reg |= AR5K_STA_ID1_NO_PSPOLL;
else
- AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC);
+ AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
break;
case NL80211_IFTYPE_STATION:
diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h
index 91aaeaf88199..9189ab13286c 100644
--- a/drivers/net/wireless/ath5k/reg.h
+++ b/drivers/net/wireless/ath5k/reg.h
@@ -73,7 +73,7 @@
#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 access */
-#define AR5K_CFG_ADHOC 0x00000020 /* AP/Adhoc indication [5211+] */
+#define AR5K_CFG_IBSS 0x00000020 /* 0-BSS, 1-IBSS [5211+] */
#define AR5K_CFG_PHY_OK 0x00000100 /* [5211+] */
#define AR5K_CFG_EEBS 0x00000200 /* EEPROM is busy */
#define AR5K_CFG_CLKGD 0x00000400 /* Clock gated (Disable dynamic clock) */
diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig
index c43bd321f97f..90a8dd873786 100644
--- a/drivers/net/wireless/ath9k/Kconfig
+++ b/drivers/net/wireless/ath9k/Kconfig
@@ -1,6 +1,7 @@
config ATH9K
tristate "Atheros 802.11n wireless cards support"
depends on PCI && MAC80211 && WLAN_80211
+ depends on RFKILL || RFKILL=n
select MAC80211_LEDS
select LEDS_CLASS
select NEW_LEDS
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 191eec50dc75..727f067aca4f 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -2164,13 +2164,13 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
conf->ht.channel_type);
}
+ ath_update_chainmask(sc, conf->ht.enabled);
+
if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) {
DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n");
mutex_unlock(&sc->mutex);
return -EINVAL;
}
-
- ath_update_chainmask(sc, conf->ht.enabled);
}
if (changed & IEEE80211_CONF_CHANGE_POWER)
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c
index 3bfc3b90f256..c92f0c6e4adc 100644
--- a/drivers/net/wireless/ath9k/xmit.c
+++ b/drivers/net/wireless/ath9k/xmit.c
@@ -126,15 +126,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
tx_info->flags |= IEEE80211_TX_STAT_ACK;
}
- tx_info->status.rates[0].count = tx_status->retries;
- if (tx_info->status.rates[0].flags & IEEE80211_TX_RC_MCS) {
- /* Change idx from internal table index to MCS index */
- int idx = tx_info->status.rates[0].idx;
- struct ath_rate_table *rate_table = sc->cur_rate_table;
- if (idx >= 0 && idx < rate_table->rate_cnt)
- tx_info->status.rates[0].idx =
- rate_table->info[idx].ratecode & 0x7f;
- }
+ tx_info->status.rates[0].count = tx_status->retries + 1;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
padsize = hdrlen & 3;
@@ -264,25 +256,22 @@ static void assign_aggr_tid_seqno(struct sk_buff *skb,
}
/* Get seqno */
-
- if (ieee80211_is_data(fc) && !is_pae(skb)) {
- /* For HT capable stations, we save tidno for later use.
- * We also override seqno set by upper layer with the one
- * in tx aggregation state.
- *
- * If fragmentation is on, the sequence number is
- * not overridden, since it has been
- * incremented by the fragmentation routine.
- *
- * FIXME: check if the fragmentation threshold exceeds
- * IEEE80211 max.
- */
- tid = ATH_AN_2_TID(an, bf->bf_tidno);
- hdr->seq_ctrl = cpu_to_le16(tid->seq_next <<
- IEEE80211_SEQ_SEQ_SHIFT);
- bf->bf_seqno = tid->seq_next;
- INCR(tid->seq_next, IEEE80211_SEQ_MAX);
- }
+ /* For HT capable stations, we save tidno for later use.
+ * We also override seqno set by upper layer with the one
+ * in tx aggregation state.
+ *
+ * If fragmentation is on, the sequence number is
+ * not overridden, since it has been
+ * incremented by the fragmentation routine.
+ *
+ * FIXME: check if the fragmentation threshold exceeds
+ * IEEE80211 max.
+ */
+ tid = ATH_AN_2_TID(an, bf->bf_tidno);
+ hdr->seq_ctrl = cpu_to_le16(tid->seq_next <<
+ IEEE80211_SEQ_SEQ_SHIFT);
+ bf->bf_seqno = tid->seq_next;
+ INCR(tid->seq_next, IEEE80211_SEQ_MAX);
}
static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb,
@@ -1718,11 +1707,10 @@ static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
/* Assign seqno, tidno */
- if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR))
+ if (ieee80211_is_data_qos(fc) && (sc->sc_flags & SC_OP_TXAGGR))
assign_aggr_tid_seqno(skb, bf);
/* DMA setup */
-
bf->bf_mpdu = skb;
bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data,
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 350157fcd080..4223672c4432 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -3836,7 +3836,7 @@ static int reset_atmel_card(struct net_device *dev)
This routine is also responsible for initialising some
hardware-specific fields in the atmel_private structure,
including a copy of the firmware's hostinfo stucture
- which is the route into the rest of the firmare datastructures. */
+ which is the route into the rest of the firmware datastructures. */
struct atmel_private *priv = netdev_priv(dev);
u8 configuration;
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 7b31a327b24a..c788bad10661 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3261,7 +3261,7 @@ static int b43_switch_band(struct b43_wl *wl, struct ieee80211_channel *chan)
struct b43_wldev *down_dev;
struct b43_wldev *d;
int err;
- bool gmode;
+ bool uninitialized_var(gmode);
int prev_status;
/* Find a device and PHY which supports the band. */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index c1324e31d2f6..fb996c27a19b 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2465,7 +2465,7 @@ static void b43legacy_put_phy_into_reset(struct b43legacy_wldev *dev)
static int b43legacy_switch_phymode(struct b43legacy_wl *wl,
unsigned int new_mode)
{
- struct b43legacy_wldev *up_dev;
+ struct b43legacy_wldev *uninitialized_var(up_dev);
struct b43legacy_wldev *down_dev;
int err;
bool gmode = 0;
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 1667065b86a7..823c2bf5e31e 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -1332,7 +1332,7 @@ static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
IPW_AUX_HOST_RESET_REG_STOP_MASTER);
/* Step 2. Wait for stop Master Assert
- * (not more then 50us, otherwise ret error */
+ * (not more than 50us, otherwise ret error */
i = 5;
do {
udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
@@ -1830,7 +1830,7 @@ static void ipw2100_down(struct ipw2100_priv *priv)
cancel_delayed_work(&priv->rf_kill);
}
- /* Kill the firmare hang check timer */
+ /* Kill the firmware hang check timer */
if (!priv->stop_hang_check) {
priv->stop_hang_check = 1;
cancel_delayed_work(&priv->hang_check);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 8fdb34222c0a..45cfa1cf194a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -2219,7 +2219,7 @@ int iwl3945_txpower_set_from_eeprom(struct iwl3945_priv *priv)
/* set tx power value for all OFDM rates */
for (rate_index = 0; rate_index < IWL_OFDM_RATES;
rate_index++) {
- s32 power_idx;
+ s32 uninitialized_var(power_idx);
int rc;
/* use channel group's clip-power table,
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 52966ffbef6e..ba997204c8d4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -255,7 +255,7 @@ struct iwl_cmd_header {
* 0x3) 54 Mbps
*
* Legacy CCK rate format for bits 7:0 (bit 8 must be "0", bit 9 "1"):
- * 3-0: 10) 1 Mbps
+ * 6-0: 10) 1 Mbps
* 20) 2 Mbps
* 55) 5.5 Mbps
* 110) 11 Mbps
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 01a2169cecec..8c71ad4f88c5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -51,6 +51,7 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(REPLY_REMOVE_STA);
IWL_CMD(REPLY_REMOVE_ALL_STA);
IWL_CMD(REPLY_WEPKEY);
+ IWL_CMD(REPLY_3945_RX);
IWL_CMD(REPLY_TX);
IWL_CMD(REPLY_RATE_SCALE);
IWL_CMD(REPLY_LEDS_CMD);
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 3dba83679444..4e0007d20030 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -1369,7 +1369,7 @@ EXPORT_SYMBOL_GPL(lbs_start_card);
void lbs_stop_card(struct lbs_private *priv)
{
- struct net_device *dev = priv->dev;
+ struct net_device *dev;
struct cmd_ctrl_node *cmdnode;
unsigned long flags;
@@ -1377,9 +1377,10 @@ void lbs_stop_card(struct lbs_private *priv)
if (!priv)
goto out;
+ dev = priv->dev;
- netif_stop_queue(priv->dev);
- netif_carrier_off(priv->dev);
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
lbs_debugfs_remove_one(priv);
if (priv->mesh_tlv) {
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index d1fc305de5fe..e7289e2e7f16 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -206,7 +206,7 @@ static int lbtf_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* there are no buffered multicast frames to send
*/
ieee80211_stop_queues(priv->hw);
- return 0;
+ return NETDEV_TX_OK;
}
static void lbtf_tx_work(struct work_struct *work)
diff --git a/drivers/net/wireless/orinoco/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c
index bc84e2792f8a..c3bb85e0251e 100644
--- a/drivers/net/wireless/orinoco/orinoco.c
+++ b/drivers/net/wireless/orinoco/orinoco.c
@@ -1610,6 +1610,16 @@ static void orinoco_rx_isr_tasklet(unsigned long data)
struct orinoco_rx_data *rx_data, *temp;
struct hermes_rx_descriptor *desc;
struct sk_buff *skb;
+ unsigned long flags;
+
+ /* orinoco_rx requires the driver lock, and we also need to
+ * protect priv->rx_list, so just hold the lock over the
+ * lot.
+ *
+ * If orinoco_lock fails, we've unplugged the card. In this
+ * case just abort. */
+ if (orinoco_lock(priv, &flags) != 0)
+ return;
/* extract desc and skb from queue */
list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
@@ -1622,6 +1632,8 @@ static void orinoco_rx_isr_tasklet(unsigned long data)
kfree(desc);
}
+
+ orinoco_unlock(priv, &flags);
}
/********************************************************************/
@@ -3645,12 +3657,22 @@ struct net_device
void free_orinocodev(struct net_device *dev)
{
struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_rx_data *rx_data, *temp;
- /* No need to empty priv->rx_list: if the tasklet is scheduled
- * when we call tasklet_kill it will run one final time,
- * emptying the list */
+ /* If the tasklet is scheduled when we call tasklet_kill it
+ * will run one final time. However the tasklet will only
+ * drain priv->rx_list if the hw is still available. */
tasklet_kill(&priv->rx_tasklet);
+ /* Explicitly drain priv->rx_list */
+ list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
+ list_del(&rx_data->list);
+
+ dev_kfree_skb(rx_data->skb);
+ kfree(rx_data->desc);
+ kfree(rx_data);
+ }
+
unregister_pm_notifier(&priv->pm_notifier);
orinoco_uncache_fw(priv);
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index f127602670ec..0b32215d3f5d 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -435,6 +435,7 @@ static struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */
PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */
PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */
+ PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0003), /* ARtem Onair Comcard 11 */
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */
PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */
PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 82354b974a04..c6a370fa9bcb 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -138,6 +138,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
u8 *fw_version = NULL;
size_t len;
int i;
+ int maxlen;
if (priv->rx_start)
return 0;
@@ -195,6 +196,16 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
else
priv->rx_mtu = (size_t)
0x620 - priv->tx_hdr_len;
+ maxlen = priv->tx_hdr_len + /* USB devices */
+ sizeof(struct p54_rx_data) +
+ 4 + /* rx alignment */
+ IEEE80211_MAX_FRAG_THRESHOLD;
+ if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
+ printk(KERN_INFO "p54: rx_mtu reduced from %d "
+ "to %d\n", priv->rx_mtu,
+ maxlen);
+ priv->rx_mtu = maxlen;
+ }
break;
}
case BR_CODE_EXPOSED_IF:
@@ -575,6 +586,7 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
u16 freq = le16_to_cpu(hdr->freq);
size_t header_len = sizeof(*hdr);
u32 tsf32;
+ u8 rate = hdr->rate & 0xf;
/*
* If the device is in a unspecified state we have to
@@ -603,8 +615,11 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
rx_status.qual = (100 * hdr->rssi) / 127;
if (hdr->rate & 0x10)
rx_status.flag |= RX_FLAG_SHORTPRE;
- rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ?
- hdr->rate : (hdr->rate - 4)) & 0xf;
+ if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
+ rx_status.rate_idx = (rate < 4) ? 0 : rate - 4;
+ else
+ rx_status.rate_idx = rate;
+
rx_status.freq = freq;
rx_status.band = dev->conf.channel->band;
rx_status.antenna = hdr->antenna;
@@ -798,6 +813,16 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
info->status.ack_signal = p54_rssi_to_dbm(dev,
(int)payload->ack_rssi);
+
+ if (entry_data->key_type == P54_CRYPTO_TKIPMICHAEL) {
+ u8 *iv = (u8 *)(entry_data->align + pad +
+ entry_data->crypt_offset);
+
+ /* Restore the original TKIP IV. */
+ iv[2] = iv[0];
+ iv[0] = iv[1];
+ iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */
+ }
skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
ieee80211_tx_status_irqsafe(dev, entry);
goto out;
@@ -1383,7 +1408,6 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
hdr->tries = ridx;
txhdr->rts_rate_idx = 0;
if (info->control.hw_key) {
- crypt_offset += info->control.hw_key->iv_len;
txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
@@ -1397,6 +1421,8 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
}
/* reserve some space for ICV */
len += info->control.hw_key->icv_len;
+ memset(skb_put(skb, info->control.hw_key->icv_len), 0,
+ info->control.hw_key->icv_len);
} else {
txhdr->key_type = 0;
txhdr->key_len = 0;
@@ -1824,7 +1850,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev,
static int p54_config(struct ieee80211_hw *dev, u32 changed)
{
- int ret;
+ int ret = 0;
struct p54_common *priv = dev->priv;
struct ieee80211_conf *conf = &dev->conf;
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index c44a200059d2..6a6a72f6f82c 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -56,6 +56,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x050d, 0x7050)}, /* Belkin F5D7050 ver 1000 */
{USB_DEVICE(0x0572, 0x2000)}, /* Cohiba Proto board */
{USB_DEVICE(0x0572, 0x2002)}, /* Cohiba Proto board */
+ {USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
{USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
{USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
{USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
@@ -284,6 +285,7 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
usb_fill_bulk_urb(data_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
skb->data, skb->len, p54u_tx_cb, skb);
+ data_urb->transfer_flags |= URB_ZERO_PACKET;
usb_anchor_urb(data_urb, &priv->submitted);
if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 30028e2422fc..af6b5847be5c 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -38,7 +38,7 @@
/*
* Allow hardware encryption to be disabled.
*/
-static int modparam_nohwcrypt = 1;
+static int modparam_nohwcrypt = 0;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
@@ -376,11 +376,11 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
/*
* The driver does not support the IV/EIV generation
- * in hardware. However it doesn't support the IV/EIV
- * inside the ieee80211 frame either, but requires it
- * to be provided seperately for the descriptor.
- * rt2x00lib will cut the IV/EIV data out of all frames
- * given to us by mac80211, but we must tell mac80211
+ * in hardware. However it demands the data to be provided
+ * both seperately as well as inside the frame.
+ * We already provided the CONFIG_CRYPTO_COPY_IV to rt2x00lib
+ * to ensure rt2x00lib will not strip the data from the
+ * frame after the copy, now we must tell mac80211
* to generate the IV/EIV data.
*/
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
@@ -1181,7 +1181,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags));
rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
- rt2x00_set_field32(&word, TXD_W0_CIPHER, txdesc->cipher);
+ rt2x00_set_field32(&word, TXD_W0_CIPHER, !!txdesc->cipher);
rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx);
rt2x00_desc_write(txd, 0, word);
}
@@ -1334,14 +1334,7 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry,
/* ICV is located at the end of frame */
- /*
- * Hardware has stripped IV/EIV data from 802.11 frame during
- * decryption. It has provided the data seperately but rt2x00lib
- * should decide if it should be reinserted.
- */
- rxdesc->flags |= RX_FLAG_IV_STRIPPED;
- if (rxdesc->cipher != CIPHER_TKIP)
- rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
+ rxdesc->flags |= RX_FLAG_MMIC_STRIPPED;
if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS)
rxdesc->flags |= RX_FLAG_DECRYPTED;
else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC)
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index 37ad0d2fb64c..aee9cba13eb3 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -184,8 +184,8 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align,
* Make room for new data, note that we increase both
* headsize and tailsize when required. The tailsize is
* only needed when ICV data needs to be inserted and
- * the padding is smaller then the ICV data.
- * When alignment requirements is greater then the
+ * the padding is smaller than the ICV data.
+ * When alignment requirements is greater than the
* ICV data we must trim the skb to the correct size
* because we need to remove the extra bytes.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 6d92542fcf0d..87c0f2c83077 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -807,13 +807,11 @@ static void rt2x00lib_rate(struct ieee80211_rate *entry,
{
entry->flags = 0;
entry->bitrate = rate->bitrate;
- entry->hw_value = rt2x00_create_rate_hw_value(index, 0);
- entry->hw_value_short = entry->hw_value;
+ entry->hw_value =index;
+ entry->hw_value_short = index;
- if (rate->flags & DEV_RATE_SHORT_PREAMBLE) {
+ if (rate->flags & DEV_RATE_SHORT_PREAMBLE)
entry->flags |= IEEE80211_RATE_SHORT_PREAMBLE;
- entry->hw_value_short |= rt2x00_create_rate_hw_value(index, 1);
- }
}
static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c
index 68f4e0fc35b9..a0cd35b6beb5 100644
--- a/drivers/net/wireless/rt2x00/rt2x00leds.c
+++ b/drivers/net/wireless/rt2x00/rt2x00leds.c
@@ -97,7 +97,7 @@ void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled)
void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled)
{
- if (rt2x00dev->led_radio.type == LED_TYPE_ASSOC)
+ if (rt2x00dev->led_radio.type == LED_TYPE_RADIO)
rt2x00led_led_simple(&rt2x00dev->led_radio, enabled);
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 03024327767b..86cd26fbf769 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -52,22 +52,11 @@ struct rt2x00_rate {
extern const struct rt2x00_rate rt2x00_supported_rates[12];
-static inline u16 rt2x00_create_rate_hw_value(const u16 index,
- const u16 short_preamble)
-{
- return (short_preamble << 8) | (index & 0xff);
-}
-
static inline const struct rt2x00_rate *rt2x00_get_rate(const u16 hw_value)
{
return &rt2x00_supported_rates[hw_value & 0xff];
}
-static inline int rt2x00_get_rate_preamble(const u16 hw_value)
-{
- return (hw_value & 0xff00);
-}
-
/*
* Radio control handlers.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index eaec6bd93ed5..746a8f36b931 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -313,7 +313,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
* When preamble is enabled we should set the
* preamble bit for the signal.
*/
- if (rt2x00_get_rate_preamble(rate->hw_value))
+ if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
txdesc->signal |= 0x08;
}
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 83df312ac56f..0b29d767a258 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -434,11 +434,11 @@ static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev)
if (usb_endpoint_is_bulk_in(ep_desc)) {
rt2x00usb_assign_endpoint(rt2x00dev->rx, ep_desc);
- } else if (usb_endpoint_is_bulk_out(ep_desc)) {
+ } else if (usb_endpoint_is_bulk_out(ep_desc) &&
+ (queue != queue_end(rt2x00dev))) {
rt2x00usb_assign_endpoint(queue, ep_desc);
+ queue = queue_next(queue);
- if (queue != queue_end(rt2x00dev))
- queue = queue_next(queue);
tx_ep_desc = ep_desc;
}
}
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index d638a8a59370..96a8d69f8790 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -2321,6 +2321,7 @@ static struct usb_device_id rt73usb_device_table[] = {
/* Linksys */
{ USB_DEVICE(0x13b1, 0x0020), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x13b1, 0x0023), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x13b1, 0x0028), USB_DEVICE_DATA(&rt73usb_ops) },
/* MSI */
{ USB_DEVICE(0x0db0, 0x6877), USB_DEVICE_DATA(&rt73usb_ops) },
{ USB_DEVICE(0x0db0, 0x6874), USB_DEVICE_DATA(&rt73usb_ops) },
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index 5f887fb137a9..387c133ec0f2 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -897,6 +897,7 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SIGNAL_UNSPEC;
+ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
dev->queues = 1;
dev->max_signal = 65;
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 00ce3ef39abe..6ad6bac37706 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -213,7 +213,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
kfree_skb(skb);
- return -ENOMEM;
+ return NETDEV_TX_OK;
}
flags = skb->len;
@@ -281,7 +281,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
}
usb_free_urb(urb);
- return rc;
+ return NETDEV_TX_OK;
}
static void rtl8187_rx_cb(struct urb *urb)
@@ -1471,6 +1471,7 @@ static void __devexit rtl8187_disconnect(struct usb_interface *intf)
ieee80211_unregister_hw(dev);
priv = dev->priv;
+ usb_reset_device(priv->udev);
usb_put_dev(interface_to_usbdev(intf));
ieee80211_free_hw(dev);
}
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index dd0de3a9ed4e..7015f2480550 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -236,7 +236,7 @@ struct strip {
unsigned long tx_errors; /* Planned stuff */
unsigned long rx_dropped; /* No memory for skb */
unsigned long tx_dropped; /* When MTU change */
- unsigned long rx_over_errors; /* Frame bigger then STRIP buf. */
+ unsigned long rx_over_errors; /* Frame bigger than STRIP buf. */
unsigned long pps_timer; /* Timer to determine pps */
unsigned long rx_pps_count; /* Counter to determine pps */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 9caa96a13586..a611ad857983 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -287,7 +287,7 @@ static void zd_op_stop(struct ieee80211_hw *hw)
* @skb - a sk-buffer
* @flags: extra flags to set in the TX status info
* @ackssi: ACK signal strength
- * @success - True for successfull transmission of the frame
+ * @success - True for successful 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
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 761635be9104..cd6184ee08ee 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1105,6 +1105,16 @@ static void xennet_uninit(struct net_device *dev)
gnttab_free_grant_references(np->gref_rx_head);
}
+static const struct net_device_ops xennet_netdev_ops = {
+ .ndo_open = xennet_open,
+ .ndo_uninit = xennet_uninit,
+ .ndo_stop = xennet_close,
+ .ndo_start_xmit = xennet_start_xmit,
+ .ndo_change_mtu = xennet_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev)
{
int i, err;
@@ -1161,12 +1171,9 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev
goto exit_free_tx;
}
- netdev->open = xennet_open;
- netdev->hard_start_xmit = xennet_start_xmit;
- netdev->stop = xennet_close;
+ netdev->netdev_ops = &xennet_netdev_ops;
+
netif_napi_add(netdev, &np->napi, xennet_poll, 64);
- netdev->uninit = xennet_uninit;
- netdev->change_mtu = xennet_change_mtu;
netdev->features = NETIF_F_IP_CSUM;
SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index cf9712922778..2f1645dcb8c8 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -362,6 +362,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_set_multicast_list = set_rx_mode,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_do_ioctl = netdev_ioctl,
.ndo_tx_timeout = yellowfin_tx_timeout,
};
diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c
index affd904deafc..37c84e3b8be0 100644
--- a/drivers/net/zorro8390.c
+++ b/drivers/net/zorro8390.c
@@ -147,6 +147,7 @@ static const struct net_device_ops zorro8390_netdev_ops = {
.ndo_get_stats = ei_get_stats,
.ndo_set_multicast_list = ei_set_multicast_list,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
.ndo_change_mtu = eth_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ei_poll,
diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c
index e1b0ad6e918f..fa65a2b2ae2e 100644
--- a/drivers/of/of_i2c.c
+++ b/drivers/of/of_i2c.c
@@ -66,4 +66,23 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
}
EXPORT_SYMBOL(of_register_i2c_devices);
+static int of_dev_node_match(struct device *dev, void *data)
+{
+ return dev_archdata_get_node(&dev->archdata) == data;
+}
+
+/* must call put_device() when done with returned i2c_client device */
+struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
+{
+ struct device *dev;
+
+ dev = bus_find_device(&i2c_bus_type, NULL, node,
+ of_dev_node_match);
+ if (!dev)
+ return NULL;
+
+ return to_i2c_client(dev);
+}
+EXPORT_SYMBOL(of_find_i2c_device_by_node);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index 65e8294a9e29..9da5a4b81133 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -1,11 +1,12 @@
/**
* @file buffer_sync.c
*
- * @remark Copyright 2002 OProfile authors
+ * @remark Copyright 2002-2009 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
* @author Barry Kasindorf
+ * @author Robert Richter <robert.richter@amd.com>
*
* This is the core of the buffer management. Each
* CPU buffer is processed and entered into the
@@ -315,88 +316,73 @@ static void add_trace_begin(void)
add_event_entry(TRACE_BEGIN_CODE);
}
-#ifdef CONFIG_OPROFILE_IBS
-
-#define IBS_FETCH_CODE_SIZE 2
-#define IBS_OP_CODE_SIZE 5
-
-/*
- * Add IBS fetch and op entries to event buffer
- */
-static void add_ibs_begin(int cpu, int code, struct mm_struct *mm)
+static void add_data(struct op_entry *entry, struct mm_struct *mm)
{
- unsigned long rip;
- int i, count;
- unsigned long ibs_cookie = 0;
+ unsigned long code, pc, val;
+ unsigned long cookie;
off_t offset;
- struct op_sample *sample;
-
- sample = cpu_buffer_read_entry(cpu);
- if (!sample)
- goto Error;
- rip = sample->eip;
-#ifdef __LP64__
- rip += sample->event << 32;
-#endif
+ if (!op_cpu_buffer_get_data(entry, &code))
+ return;
+ if (!op_cpu_buffer_get_data(entry, &pc))
+ return;
+ if (!op_cpu_buffer_get_size(entry))
+ return;
if (mm) {
- ibs_cookie = lookup_dcookie(mm, rip, &offset);
+ cookie = lookup_dcookie(mm, pc, &offset);
- if (ibs_cookie == NO_COOKIE)
- offset = rip;
- if (ibs_cookie == INVALID_COOKIE) {
+ if (cookie == NO_COOKIE)
+ offset = pc;
+ if (cookie == INVALID_COOKIE) {
atomic_inc(&oprofile_stats.sample_lost_no_mapping);
- offset = rip;
+ offset = pc;
}
- if (ibs_cookie != last_cookie) {
- add_cookie_switch(ibs_cookie);
- last_cookie = ibs_cookie;
+ if (cookie != last_cookie) {
+ add_cookie_switch(cookie);
+ last_cookie = cookie;
}
} else
- offset = rip;
+ offset = pc;
add_event_entry(ESCAPE_CODE);
add_event_entry(code);
add_event_entry(offset); /* Offset from Dcookie */
- /* we send the Dcookie offset, but send the raw Linear Add also*/
- add_event_entry(sample->eip);
- add_event_entry(sample->event);
-
- if (code == IBS_FETCH_CODE)
- count = IBS_FETCH_CODE_SIZE; /*IBS FETCH is 2 int64s*/
- else
- count = IBS_OP_CODE_SIZE; /*IBS OP is 5 int64s*/
-
- for (i = 0; i < count; i++) {
- sample = cpu_buffer_read_entry(cpu);
- if (!sample)
- goto Error;
- add_event_entry(sample->eip);
- add_event_entry(sample->event);
- }
-
- return;
-
-Error:
- return;
+ while (op_cpu_buffer_get_data(entry, &val))
+ add_event_entry(val);
}
-#endif
-
-static void add_sample_entry(unsigned long offset, unsigned long event)
+static inline void add_sample_entry(unsigned long offset, unsigned long event)
{
add_event_entry(offset);
add_event_entry(event);
}
-static int add_us_sample(struct mm_struct *mm, struct op_sample *s)
+/*
+ * Add a sample to the global event buffer. If possible the
+ * sample is converted into a persistent dentry/offset pair
+ * for later lookup from userspace. Return 0 on failure.
+ */
+static int
+add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel)
{
unsigned long cookie;
off_t offset;
+ if (in_kernel) {
+ add_sample_entry(s->eip, s->event);
+ return 1;
+ }
+
+ /* add userspace sample */
+
+ if (!mm) {
+ atomic_inc(&oprofile_stats.sample_lost_no_mm);
+ return 0;
+ }
+
cookie = lookup_dcookie(mm, s->eip, &offset);
if (cookie == INVALID_COOKIE) {
@@ -415,25 +401,6 @@ static int add_us_sample(struct mm_struct *mm, struct op_sample *s)
}
-/* Add a sample to the global event buffer. If possible the
- * sample is converted into a persistent dentry/offset pair
- * for later lookup from userspace.
- */
-static int
-add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel)
-{
- if (in_kernel) {
- add_sample_entry(s->eip, s->event);
- return 1;
- } else if (mm) {
- return add_us_sample(mm, s);
- } else {
- atomic_inc(&oprofile_stats.sample_lost_no_mm);
- }
- return 0;
-}
-
-
static void release_mm(struct mm_struct *mm)
{
if (!mm)
@@ -526,66 +493,69 @@ void sync_buffer(int cpu)
{
struct mm_struct *mm = NULL;
struct mm_struct *oldmm;
+ unsigned long val;
struct task_struct *new;
unsigned long cookie = 0;
int in_kernel = 1;
sync_buffer_state state = sb_buffer_start;
unsigned int i;
unsigned long available;
+ unsigned long flags;
+ struct op_entry entry;
+ struct op_sample *sample;
mutex_lock(&buffer_mutex);
add_cpu_switch(cpu);
- cpu_buffer_reset(cpu);
- available = cpu_buffer_entries(cpu);
+ op_cpu_buffer_reset(cpu);
+ available = op_cpu_buffer_entries(cpu);
for (i = 0; i < available; ++i) {
- struct op_sample *s = cpu_buffer_read_entry(cpu);
- if (!s)
+ sample = op_cpu_buffer_read_entry(&entry, cpu);
+ if (!sample)
break;
- if (is_code(s->eip)) {
- switch (s->event) {
- case 0:
- case CPU_IS_KERNEL:
+ if (is_code(sample->eip)) {
+ flags = sample->event;
+ if (flags & TRACE_BEGIN) {
+ state = sb_bt_start;
+ add_trace_begin();
+ }
+ if (flags & KERNEL_CTX_SWITCH) {
/* kernel/userspace switch */
- in_kernel = s->event;
+ in_kernel = flags & IS_KERNEL;
if (state == sb_buffer_start)
state = sb_sample_start;
- add_kernel_ctx_switch(s->event);
- break;
- case CPU_TRACE_BEGIN:
- state = sb_bt_start;
- add_trace_begin();
- break;
-#ifdef CONFIG_OPROFILE_IBS
- case IBS_FETCH_BEGIN:
- state = sb_bt_start;
- add_ibs_begin(cpu, IBS_FETCH_CODE, mm);
- break;
- case IBS_OP_BEGIN:
- state = sb_bt_start;
- add_ibs_begin(cpu, IBS_OP_CODE, mm);
- break;
-#endif
- default:
+ add_kernel_ctx_switch(flags & IS_KERNEL);
+ }
+ if (flags & USER_CTX_SWITCH
+ && op_cpu_buffer_get_data(&entry, &val)) {
/* userspace context switch */
+ new = (struct task_struct *)val;
oldmm = mm;
- new = (struct task_struct *)s->event;
release_mm(oldmm);
mm = take_tasks_mm(new);
if (mm != oldmm)
cookie = get_exec_dcookie(mm);
add_user_ctx_switch(new, cookie);
- break;
- }
- } else if (state >= sb_bt_start &&
- !add_sample(mm, s, in_kernel)) {
- if (state == sb_bt_start) {
- state = sb_bt_ignore;
- atomic_inc(&oprofile_stats.bt_lost_no_mapping);
}
+ if (op_cpu_buffer_get_size(&entry))
+ add_data(&entry, mm);
+ continue;
+ }
+
+ if (state < sb_bt_start)
+ /* ignore sample */
+ continue;
+
+ if (add_sample(mm, sample, in_kernel))
+ continue;
+
+ /* ignore backtraces if failed to add a sample */
+ if (state == sb_bt_start) {
+ state = sb_bt_ignore;
+ atomic_inc(&oprofile_stats.bt_lost_no_mapping);
}
}
release_mm(mm);
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
index 61090969158f..2e03b6d796d3 100644
--- a/drivers/oprofile/cpu_buffer.c
+++ b/drivers/oprofile/cpu_buffer.c
@@ -1,11 +1,12 @@
/**
* @file cpu_buffer.c
*
- * @remark Copyright 2002 OProfile authors
+ * @remark Copyright 2002-2009 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
* @author Barry Kasindorf <barry.kasindorf@amd.com>
+ * @author Robert Richter <robert.richter@amd.com>
*
* Each CPU has a local buffer that stores PC value/event
* pairs. We also log context switches when we notice them.
@@ -45,8 +46,8 @@
* can be changed to a single buffer solution when the ring buffer
* access is implemented as non-locking atomic code.
*/
-struct ring_buffer *op_ring_buffer_read;
-struct ring_buffer *op_ring_buffer_write;
+static struct ring_buffer *op_ring_buffer_read;
+static struct ring_buffer *op_ring_buffer_write;
DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer);
static void wq_sync_buffer(struct work_struct *work);
@@ -54,19 +55,9 @@ static void wq_sync_buffer(struct work_struct *work);
#define DEFAULT_TIMER_EXPIRE (HZ / 10)
static int work_enabled;
-void free_cpu_buffers(void)
-{
- if (op_ring_buffer_read)
- ring_buffer_free(op_ring_buffer_read);
- op_ring_buffer_read = NULL;
- if (op_ring_buffer_write)
- ring_buffer_free(op_ring_buffer_write);
- op_ring_buffer_write = NULL;
-}
-
unsigned long oprofile_get_cpu_buffer_size(void)
{
- return fs_cpu_buffer_size;
+ return oprofile_cpu_buffer_size;
}
void oprofile_cpu_buffer_inc_smpl_lost(void)
@@ -77,11 +68,21 @@ void oprofile_cpu_buffer_inc_smpl_lost(void)
cpu_buf->sample_lost_overflow++;
}
+void free_cpu_buffers(void)
+{
+ if (op_ring_buffer_read)
+ ring_buffer_free(op_ring_buffer_read);
+ op_ring_buffer_read = NULL;
+ if (op_ring_buffer_write)
+ ring_buffer_free(op_ring_buffer_write);
+ op_ring_buffer_write = NULL;
+}
+
int alloc_cpu_buffers(void)
{
int i;
- unsigned long buffer_size = fs_cpu_buffer_size;
+ unsigned long buffer_size = oprofile_cpu_buffer_size;
op_ring_buffer_read = ring_buffer_alloc(buffer_size, OP_BUFFER_FLAGS);
if (!op_ring_buffer_read)
@@ -97,8 +98,6 @@ int alloc_cpu_buffers(void)
b->last_is_kernel = -1;
b->tracing = 0;
b->buffer_size = buffer_size;
- b->tail_pos = 0;
- b->head_pos = 0;
b->sample_received = 0;
b->sample_lost_overflow = 0;
b->backtrace_aborted = 0;
@@ -145,47 +144,156 @@ void end_cpu_work(void)
flush_scheduled_work();
}
-static inline int
-add_sample(struct oprofile_cpu_buffer *cpu_buf,
- unsigned long pc, unsigned long event)
+/*
+ * This function prepares the cpu buffer to write a sample.
+ *
+ * Struct op_entry is used during operations on the ring buffer while
+ * struct op_sample contains the data that is stored in the ring
+ * buffer. Struct entry can be uninitialized. The function reserves a
+ * data array that is specified by size. Use
+ * op_cpu_buffer_write_commit() after preparing the sample. In case of
+ * errors a null pointer is returned, otherwise the pointer to the
+ * sample.
+ *
+ */
+struct op_sample
+*op_cpu_buffer_write_reserve(struct op_entry *entry, unsigned long size)
+{
+ entry->event = ring_buffer_lock_reserve
+ (op_ring_buffer_write, sizeof(struct op_sample) +
+ size * sizeof(entry->sample->data[0]), &entry->irq_flags);
+ if (entry->event)
+ entry->sample = ring_buffer_event_data(entry->event);
+ else
+ entry->sample = NULL;
+
+ if (!entry->sample)
+ return NULL;
+
+ entry->size = size;
+ entry->data = entry->sample->data;
+
+ return entry->sample;
+}
+
+int op_cpu_buffer_write_commit(struct op_entry *entry)
+{
+ return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event,
+ entry->irq_flags);
+}
+
+struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu)
+{
+ struct ring_buffer_event *e;
+ e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL);
+ if (e)
+ goto event;
+ if (ring_buffer_swap_cpu(op_ring_buffer_read,
+ op_ring_buffer_write,
+ cpu))
+ return NULL;
+ e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL);
+ if (e)
+ goto event;
+ return NULL;
+
+event:
+ entry->event = e;
+ entry->sample = ring_buffer_event_data(e);
+ entry->size = (ring_buffer_event_length(e) - sizeof(struct op_sample))
+ / sizeof(entry->sample->data[0]);
+ entry->data = entry->sample->data;
+ return entry->sample;
+}
+
+unsigned long op_cpu_buffer_entries(int cpu)
+{
+ return ring_buffer_entries_cpu(op_ring_buffer_read, cpu)
+ + ring_buffer_entries_cpu(op_ring_buffer_write, cpu);
+}
+
+static int
+op_add_code(struct oprofile_cpu_buffer *cpu_buf, unsigned long backtrace,
+ int is_kernel, struct task_struct *task)
{
struct op_entry entry;
- int ret;
+ struct op_sample *sample;
+ unsigned long flags;
+ int size;
+
+ flags = 0;
+
+ if (backtrace)
+ flags |= TRACE_BEGIN;
+
+ /* notice a switch from user->kernel or vice versa */
+ is_kernel = !!is_kernel;
+ if (cpu_buf->last_is_kernel != is_kernel) {
+ cpu_buf->last_is_kernel = is_kernel;
+ flags |= KERNEL_CTX_SWITCH;
+ if (is_kernel)
+ flags |= IS_KERNEL;
+ }
+
+ /* notice a task switch */
+ if (cpu_buf->last_task != task) {
+ cpu_buf->last_task = task;
+ flags |= USER_CTX_SWITCH;
+ }
+
+ if (!flags)
+ /* nothing to do */
+ return 0;
+
+ if (flags & USER_CTX_SWITCH)
+ size = 1;
+ else
+ size = 0;
+
+ sample = op_cpu_buffer_write_reserve(&entry, size);
+ if (!sample)
+ return -ENOMEM;
- ret = cpu_buffer_write_entry(&entry);
- if (ret)
- return ret;
+ sample->eip = ESCAPE_CODE;
+ sample->event = flags;
- entry.sample->eip = pc;
- entry.sample->event = event;
+ if (size)
+ op_cpu_buffer_add_data(&entry, (unsigned long)task);
- ret = cpu_buffer_write_commit(&entry);
- if (ret)
- return ret;
+ op_cpu_buffer_write_commit(&entry);
return 0;
}
static inline int
-add_code(struct oprofile_cpu_buffer *buffer, unsigned long value)
+op_add_sample(struct oprofile_cpu_buffer *cpu_buf,
+ unsigned long pc, unsigned long event)
{
- return add_sample(buffer, ESCAPE_CODE, value);
+ struct op_entry entry;
+ struct op_sample *sample;
+
+ sample = op_cpu_buffer_write_reserve(&entry, 0);
+ if (!sample)
+ return -ENOMEM;
+
+ sample->eip = pc;
+ sample->event = event;
+
+ return op_cpu_buffer_write_commit(&entry);
}
-/* This must be safe from any context. It's safe writing here
- * because of the head/tail separation of the writer and reader
- * of the CPU buffer.
+/*
+ * This must be safe from any context.
*
* is_kernel is needed because on some architectures you cannot
* tell if you are in kernel or user space simply by looking at
* pc. We tag this in the buffer by generating kernel enter/exit
* events whenever is_kernel changes
*/
-static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
- int is_kernel, unsigned long event)
+static int
+log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
+ unsigned long backtrace, int is_kernel, unsigned long event)
{
- struct task_struct *task;
-
cpu_buf->sample_received++;
if (pc == ESCAPE_CODE) {
@@ -193,25 +301,10 @@ static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc,
return 0;
}
- is_kernel = !!is_kernel;
-
- task = current;
-
- /* notice a switch from user->kernel or vice versa */
- if (cpu_buf->last_is_kernel != is_kernel) {
- cpu_buf->last_is_kernel = is_kernel;
- if (add_code(cpu_buf, is_kernel))
- goto fail;
- }
-
- /* notice a task switch */
- if (cpu_buf->last_task != task) {
- cpu_buf->last_task = task;
- if (add_code(cpu_buf, (unsigned long)task))
- goto fail;
- }
+ if (op_add_code(cpu_buf, backtrace, is_kernel, current))
+ goto fail;
- if (add_sample(cpu_buf, pc, event))
+ if (op_add_sample(cpu_buf, pc, event))
goto fail;
return 1;
@@ -221,109 +314,102 @@ fail:
return 0;
}
-static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf)
+static inline void oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf)
{
- add_code(cpu_buf, CPU_TRACE_BEGIN);
cpu_buf->tracing = 1;
- return 1;
}
-static void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf)
+static inline void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf)
{
cpu_buf->tracing = 0;
}
-void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
- unsigned long event, int is_kernel)
+static inline void
+__oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
+ unsigned long event, int is_kernel)
{
struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
-
- if (!backtrace_depth) {
- log_sample(cpu_buf, pc, is_kernel, event);
- return;
- }
-
- if (!oprofile_begin_trace(cpu_buf))
- return;
+ unsigned long backtrace = oprofile_backtrace_depth;
/*
* if log_sample() fail we can't backtrace since we lost the
* source of this event
*/
- if (log_sample(cpu_buf, pc, is_kernel, event))
- oprofile_ops.backtrace(regs, backtrace_depth);
+ if (!log_sample(cpu_buf, pc, backtrace, is_kernel, event))
+ /* failed */
+ return;
+
+ if (!backtrace)
+ return;
+
+ oprofile_begin_trace(cpu_buf);
+ oprofile_ops.backtrace(regs, backtrace);
oprofile_end_trace(cpu_buf);
}
+void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
+ unsigned long event, int is_kernel)
+{
+ __oprofile_add_ext_sample(pc, regs, event, is_kernel);
+}
+
void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
{
int is_kernel = !user_mode(regs);
unsigned long pc = profile_pc(regs);
- oprofile_add_ext_sample(pc, regs, event, is_kernel);
+ __oprofile_add_ext_sample(pc, regs, event, is_kernel);
}
-#ifdef CONFIG_OPROFILE_IBS
-
-#define MAX_IBS_SAMPLE_SIZE 14
-
-void oprofile_add_ibs_sample(struct pt_regs * const regs,
- unsigned int * const ibs_sample, int ibs_code)
+/*
+ * Add samples with data to the ring buffer.
+ *
+ * Use oprofile_add_data(&entry, val) to add data and
+ * oprofile_write_commit(&entry) to commit the sample.
+ */
+void
+oprofile_write_reserve(struct op_entry *entry, struct pt_regs * const regs,
+ unsigned long pc, int code, int size)
{
+ struct op_sample *sample;
int is_kernel = !user_mode(regs);
struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
- struct task_struct *task;
- int fail = 0;
cpu_buf->sample_received++;
- /* notice a switch from user->kernel or vice versa */
- if (cpu_buf->last_is_kernel != is_kernel) {
- if (add_code(cpu_buf, is_kernel))
- goto fail;
- cpu_buf->last_is_kernel = is_kernel;
- }
-
- /* notice a task switch */
- if (!is_kernel) {
- task = current;
- if (cpu_buf->last_task != task) {
- if (add_code(cpu_buf, (unsigned long)task))
- goto fail;
- cpu_buf->last_task = task;
- }
- }
-
- fail = fail || add_code(cpu_buf, ibs_code);
- fail = fail || add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]);
- fail = fail || add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]);
- fail = fail || add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]);
-
- if (ibs_code == IBS_OP_BEGIN) {
- fail = fail || add_sample(cpu_buf, ibs_sample[6], ibs_sample[7]);
- fail = fail || add_sample(cpu_buf, ibs_sample[8], ibs_sample[9]);
- fail = fail || add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]);
- }
+ /* no backtraces for samples with data */
+ if (op_add_code(cpu_buf, 0, is_kernel, current))
+ goto fail;
- if (fail)
+ sample = op_cpu_buffer_write_reserve(entry, size + 2);
+ if (!sample)
goto fail;
+ sample->eip = ESCAPE_CODE;
+ sample->event = 0; /* no flags */
- if (backtrace_depth)
- oprofile_ops.backtrace(regs, backtrace_depth);
+ op_cpu_buffer_add_data(entry, code);
+ op_cpu_buffer_add_data(entry, pc);
return;
fail:
cpu_buf->sample_lost_overflow++;
- return;
}
-#endif
+int oprofile_add_data(struct op_entry *entry, unsigned long val)
+{
+ return op_cpu_buffer_add_data(entry, val);
+}
+
+int oprofile_write_commit(struct op_entry *entry)
+{
+ return op_cpu_buffer_write_commit(entry);
+}
void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event)
{
struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
- log_sample(cpu_buf, pc, is_kernel, event);
+ log_sample(cpu_buf, pc, 0, is_kernel, event);
}
void oprofile_add_trace(unsigned long pc)
@@ -340,7 +426,7 @@ void oprofile_add_trace(unsigned long pc)
if (pc == ESCAPE_CODE)
goto fail;
- if (add_sample(cpu_buf, pc, 0))
+ if (op_add_sample(cpu_buf, pc, 0))
goto fail;
return;
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h
index aacb0f0bc566..63f81c44846a 100644
--- a/drivers/oprofile/cpu_buffer.h
+++ b/drivers/oprofile/cpu_buffer.h
@@ -1,10 +1,11 @@
/**
* @file cpu_buffer.h
*
- * @remark Copyright 2002 OProfile authors
+ * @remark Copyright 2002-2009 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
+ * @author Robert Richter <robert.richter@amd.com>
*/
#ifndef OPROFILE_CPU_BUFFER_H
@@ -31,17 +32,12 @@ void end_cpu_work(void);
struct op_sample {
unsigned long eip;
unsigned long event;
+ unsigned long data[0];
};
-struct op_entry {
- struct ring_buffer_event *event;
- struct op_sample *sample;
- unsigned long irq_flags;
-};
+struct op_entry;
struct oprofile_cpu_buffer {
- volatile unsigned long head_pos;
- volatile unsigned long tail_pos;
unsigned long buffer_size;
struct task_struct *last_task;
int last_is_kernel;
@@ -54,8 +50,6 @@ struct oprofile_cpu_buffer {
struct delayed_work work;
};
-extern struct ring_buffer *op_ring_buffer_read;
-extern struct ring_buffer *op_ring_buffer_write;
DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer);
/*
@@ -64,7 +58,7 @@ DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer);
* reset these to invalid values; the next sample collected will
* populate the buffer with proper values to initialize the buffer
*/
-static inline void cpu_buffer_reset(int cpu)
+static inline void op_cpu_buffer_reset(int cpu)
{
struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu);
@@ -72,55 +66,48 @@ static inline void cpu_buffer_reset(int cpu)
cpu_buf->last_task = NULL;
}
-static inline int cpu_buffer_write_entry(struct op_entry *entry)
-{
- entry->event = ring_buffer_lock_reserve(op_ring_buffer_write,
- sizeof(struct op_sample),
- &entry->irq_flags);
- if (entry->event)
- entry->sample = ring_buffer_event_data(entry->event);
- else
- entry->sample = NULL;
-
- if (!entry->sample)
- return -ENOMEM;
-
- return 0;
-}
+struct op_sample
+*op_cpu_buffer_write_reserve(struct op_entry *entry, unsigned long size);
+int op_cpu_buffer_write_commit(struct op_entry *entry);
+struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu);
+unsigned long op_cpu_buffer_entries(int cpu);
-static inline int cpu_buffer_write_commit(struct op_entry *entry)
+/* returns the remaining free size of data in the entry */
+static inline
+int op_cpu_buffer_add_data(struct op_entry *entry, unsigned long val)
{
- return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event,
- entry->irq_flags);
+ if (!entry->size)
+ return 0;
+ *entry->data = val;
+ entry->size--;
+ entry->data++;
+ return entry->size;
}
-static inline struct op_sample *cpu_buffer_read_entry(int cpu)
+/* returns the size of data in the entry */
+static inline
+int op_cpu_buffer_get_size(struct op_entry *entry)
{
- struct ring_buffer_event *e;
- e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL);
- if (e)
- return ring_buffer_event_data(e);
- if (ring_buffer_swap_cpu(op_ring_buffer_read,
- op_ring_buffer_write,
- cpu))
- return NULL;
- e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL);
- if (e)
- return ring_buffer_event_data(e);
- return NULL;
+ return entry->size;
}
-/* "acquire" as many cpu buffer slots as we can */
-static inline unsigned long cpu_buffer_entries(int cpu)
+/* returns 0 if empty or the size of data including the current value */
+static inline
+int op_cpu_buffer_get_data(struct op_entry *entry, unsigned long *val)
{
- return ring_buffer_entries_cpu(op_ring_buffer_read, cpu)
- + ring_buffer_entries_cpu(op_ring_buffer_write, cpu);
+ int size = entry->size;
+ if (!size)
+ return 0;
+ *val = *entry->data;
+ entry->size--;
+ entry->data++;
+ return size;
}
-/* transient events for the CPU buffer -> event buffer */
-#define CPU_IS_KERNEL 1
-#define CPU_TRACE_BEGIN 2
-#define IBS_FETCH_BEGIN 3
-#define IBS_OP_BEGIN 4
+/* extra data flags */
+#define KERNEL_CTX_SWITCH (1UL << 0)
+#define IS_KERNEL (1UL << 1)
+#define TRACE_BEGIN (1UL << 2)
+#define USER_CTX_SWITCH (1UL << 3)
#endif /* OPROFILE_CPU_BUFFER_H */
diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c
index 191a3202cecc..2b7ae366ceb1 100644
--- a/drivers/oprofile/event_buffer.c
+++ b/drivers/oprofile/event_buffer.c
@@ -73,8 +73,8 @@ int alloc_event_buffer(void)
unsigned long flags;
spin_lock_irqsave(&oprofilefs_lock, flags);
- buffer_size = fs_buffer_size;
- buffer_watershed = fs_buffer_watershed;
+ buffer_size = oprofile_buffer_size;
+ buffer_watershed = oprofile_buffer_watershed;
spin_unlock_irqrestore(&oprofilefs_lock, flags);
if (buffer_watershed >= buffer_size)
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index cd375907f26f..3cffce90f82a 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -23,7 +23,7 @@
struct oprofile_operations oprofile_ops;
unsigned long oprofile_started;
-unsigned long backtrace_depth;
+unsigned long oprofile_backtrace_depth;
static unsigned long is_setup;
static DEFINE_MUTEX(start_mutex);
@@ -172,7 +172,7 @@ int oprofile_set_backtrace(unsigned long val)
goto out;
}
- backtrace_depth = val;
+ oprofile_backtrace_depth = val;
out:
mutex_unlock(&start_mutex);
diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h
index 5df0c21a608f..c288d3c24b50 100644
--- a/drivers/oprofile/oprof.h
+++ b/drivers/oprofile/oprof.h
@@ -21,12 +21,12 @@ void oprofile_stop(void);
struct oprofile_operations;
-extern unsigned long fs_buffer_size;
-extern unsigned long fs_cpu_buffer_size;
-extern unsigned long fs_buffer_watershed;
+extern unsigned long oprofile_buffer_size;
+extern unsigned long oprofile_cpu_buffer_size;
+extern unsigned long oprofile_buffer_watershed;
extern struct oprofile_operations oprofile_ops;
extern unsigned long oprofile_started;
-extern unsigned long backtrace_depth;
+extern unsigned long oprofile_backtrace_depth;
struct super_block;
struct dentry;
diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c
index d8201998b0b7..5d36ffc30dd5 100644
--- a/drivers/oprofile/oprofile_files.c
+++ b/drivers/oprofile/oprofile_files.c
@@ -14,17 +14,18 @@
#include "oprofile_stats.h"
#include "oprof.h"
-#define FS_BUFFER_SIZE_DEFAULT 131072
-#define FS_CPU_BUFFER_SIZE_DEFAULT 8192
-#define FS_BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */
+#define BUFFER_SIZE_DEFAULT 131072
+#define CPU_BUFFER_SIZE_DEFAULT 8192
+#define BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */
-unsigned long fs_buffer_size;
-unsigned long fs_cpu_buffer_size;
-unsigned long fs_buffer_watershed;
+unsigned long oprofile_buffer_size;
+unsigned long oprofile_cpu_buffer_size;
+unsigned long oprofile_buffer_watershed;
static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
- return oprofilefs_ulong_to_user(backtrace_depth, buf, count, offset);
+ return oprofilefs_ulong_to_user(oprofile_backtrace_depth, buf, count,
+ offset);
}
@@ -125,16 +126,16 @@ static const struct file_operations dump_fops = {
void oprofile_create_files(struct super_block *sb, struct dentry *root)
{
/* reinitialize default values */
- fs_buffer_size = FS_BUFFER_SIZE_DEFAULT;
- fs_cpu_buffer_size = FS_CPU_BUFFER_SIZE_DEFAULT;
- fs_buffer_watershed = FS_BUFFER_WATERSHED_DEFAULT;
+ oprofile_buffer_size = BUFFER_SIZE_DEFAULT;
+ oprofile_cpu_buffer_size = CPU_BUFFER_SIZE_DEFAULT;
+ oprofile_buffer_watershed = BUFFER_WATERSHED_DEFAULT;
oprofilefs_create_file(sb, root, "enable", &enable_fops);
oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666);
oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops);
- oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size);
- oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed);
- oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &fs_cpu_buffer_size);
+ oprofilefs_create_ulong(sb, root, "buffer_size", &oprofile_buffer_size);
+ oprofilefs_create_ulong(sb, root, "buffer_watershed", &oprofile_buffer_watershed);
+ oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &oprofile_cpu_buffer_size);
oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops);
oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops);
oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops);
diff --git a/drivers/parisc/asp.c b/drivers/parisc/asp.c
index 821369135369..7931133526c4 100644
--- a/drivers/parisc/asp.c
+++ b/drivers/parisc/asp.c
@@ -71,8 +71,7 @@ static void asp_choose_irq(struct parisc_device *dev, void *ctrl)
*/
#define ASP_INTERRUPT_ADDR 0xf0800000
-int __init
-asp_init_chip(struct parisc_device *dev)
+static int __init asp_init_chip(struct parisc_device *dev)
{
struct gsc_irq gsc_irq;
int ret;
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index dcc1e9958d2f..cd4dd7ed2c06 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -555,7 +555,7 @@ static u32 hint_lookup[] = {
* (Load Coherence Index) instruction. The 8 bits used for the virtual
* index are bits 12:19 of the value returned by LCI.
*/
-void CCIO_INLINE
+static void CCIO_INLINE
ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
unsigned long hints)
{
@@ -1578,8 +1578,6 @@ static int __init ccio_probe(struct parisc_device *dev)
ioc_count++;
- parisc_vmerge_boundary = IOVP_SIZE;
- parisc_vmerge_max_size = BITS_PER_LONG * IOVP_SIZE;
parisc_has_iommu();
return 0;
}
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 3bc54b30c3a1..d539d9df88e7 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -287,7 +287,7 @@ DINO_PORT_OUT(b, 8, 3)
DINO_PORT_OUT(w, 16, 2)
DINO_PORT_OUT(l, 32, 0)
-struct pci_port_ops dino_port_ops = {
+static struct pci_port_ops dino_port_ops = {
.inb = dino_in8,
.inw = dino_in16,
.inl = dino_in32,
@@ -547,7 +547,7 @@ dino_card_fixup(struct pci_dev *dev)
** The additional "-1" adjusts for skewing the IRQ<->slot.
*/
dino_cfg_read(dev->bus, dev->devfn, PCI_INTERRUPT_PIN, 1, &irq_pin);
- dev->irq = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ;
+ dev->irq = pci_swizzle_interrupt_pin(dev, irq_pin) - 1;
/* Shouldn't really need to do this but it's in case someone tries
** to bypass PCI services and look at the card themselves.
@@ -672,7 +672,7 @@ dino_fixup_bus(struct pci_bus *bus)
dino_cfg_read(dev->bus, dev->devfn,
PCI_INTERRUPT_PIN, 1, &irq_pin);
- irq_pin = (irq_pin + PCI_SLOT(dev->devfn) - 1) % 4 ;
+ irq_pin = pci_swizzle_interrupt_pin(dev, irq_pin) - 1;
printk(KERN_WARNING "Device %s has undefined IRQ, "
"setting to %d\n", pci_name(dev), irq_pin);
dino_cfg_write(dev->bus, dev->devfn,
@@ -690,7 +690,7 @@ dino_fixup_bus(struct pci_bus *bus)
}
-struct pci_bios_ops dino_bios_ops = {
+static struct pci_bios_ops dino_bios_ops = {
.init = dino_bios_init,
.fixup_bus = dino_fixup_bus
};
diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c
index 65eee67aa2ae..13856415b432 100644
--- a/drivers/parisc/hppb.c
+++ b/drivers/parisc/hppb.c
@@ -29,7 +29,7 @@ struct hppb_card {
struct hppb_card *next;
};
-struct hppb_card hppb_card_head = {
+static struct hppb_card hppb_card_head = {
.hpa = 0,
.next = NULL,
};
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index 9dedbbd218c3..0797659ee016 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -519,8 +519,7 @@ iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev)
**
** Advantage is it's really easy to implement.
*/
- intr_pin = ((intr_pin-1)+PCI_SLOT(pcidev->devfn)) % 4;
- intr_pin++; /* convert back to INTA-D (1-4) */
+ intr_pin = pci_swizzle_interrupt_pin(pcidev, intr_pin);
#endif /* PCI_BRIDGE_FUNCS */
/*
diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c
index bee510098ce8..e65727ca9fc0 100644
--- a/drivers/parisc/lasi.c
+++ b/drivers/parisc/lasi.c
@@ -107,7 +107,7 @@ lasi_init_irq(struct gsc_asic *this_lasi)
#else
-void __init lasi_led_init(unsigned long lasi_hpa)
+static void __init lasi_led_init(unsigned long lasi_hpa)
{
unsigned long datareg;
@@ -163,8 +163,7 @@ static void lasi_power_off(void)
gsc_writel(0x02, datareg);
}
-int __init
-lasi_init_chip(struct parisc_device *dev)
+static int __init lasi_init_chip(struct parisc_device *dev)
{
extern void (*chassis_power_off)(void);
struct gsc_asic *lasi;
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index a28c8946deaa..d8233de8c75d 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -824,7 +824,7 @@ lba_fixup_bus(struct pci_bus *bus)
}
-struct pci_bios_ops lba_bios_ops = {
+static struct pci_bios_ops lba_bios_ops = {
.init = lba_bios_init,
.fixup_bus = lba_fixup_bus,
};
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index bc73b96346ff..3fac8f81d59d 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -561,7 +561,7 @@ typedef unsigned long space_t;
* IOMMU uses little endian for the pdir.
*/
-void SBA_INLINE
+static void SBA_INLINE
sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
unsigned long hint)
{
@@ -1874,7 +1874,7 @@ static struct parisc_device_id sba_tbl[] = {
{ 0, }
};
-int sba_driver_callback(struct parisc_device *);
+static int sba_driver_callback(struct parisc_device *);
static struct parisc_driver sba_driver = {
.name = MODULE_NAME,
@@ -1887,8 +1887,7 @@ static struct parisc_driver sba_driver = {
** If so, initialize the chip and tell other partners in crime they
** have work to do.
*/
-int
-sba_driver_callback(struct parisc_device *dev)
+static int sba_driver_callback(struct parisc_device *dev)
{
struct sba_device *sba_dev;
u32 func_class;
@@ -1979,8 +1978,6 @@ sba_driver_callback(struct parisc_device *dev)
proc_create("sba_iommu-bitmap", 0, root, &sba_proc_bitmap_fops);
#endif
- parisc_vmerge_boundary = IOVP_SIZE;
- parisc_vmerge_max_size = IOVP_SIZE * BITS_PER_LONG;
parisc_has_iommu();
return 0;
}
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index 1e93c837514f..4fa3bb2ddfe4 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -405,7 +405,6 @@ static void __init superio_serial_init(void)
serial_port.type = PORT_16550A;
serial_port.uartclk = 115200*16;
serial_port.fifosize = 16;
- spin_lock_init(&serial_port.lock);
/* serial port #1 */
serial_port.iobase = sio_dev.sp1_base;
diff --git a/drivers/parisc/wax.c b/drivers/parisc/wax.c
index 892a83bbe73d..da9d5ad1353c 100644
--- a/drivers/parisc/wax.c
+++ b/drivers/parisc/wax.c
@@ -68,8 +68,7 @@ wax_init_irq(struct gsc_asic *wax)
// gsc_writel(0xFFFFFFFF, base+0x2000); /* RS232-B on Wax */
}
-int __init
-wax_init_chip(struct parisc_device *dev)
+static int __init wax_init_chip(struct parisc_device *dev)
{
struct gsc_asic *wax;
struct parisc_device *parent;
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index e1ca42591ac4..2a4501dd2515 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -42,6 +42,15 @@ config PCI_DEBUG
When in doubt, say N.
+config PCI_STUB
+ tristate "PCI Stub driver"
+ depends on PCI
+ help
+ Say Y or M here if you want be able to reserve a PCI device
+ when it is going to be assigned to a guest operating system.
+
+ When in doubt, say N.
+
config HT_IRQ
bool "Interrupts on hypertransport devices"
default y
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index af3bfe22847b..3d07ce24f6a8 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -53,6 +53,8 @@ obj-$(CONFIG_HOTPLUG) += setup-bus.o
obj-$(CONFIG_PCI_SYSCALL) += syscall.o
+obj-$(CONFIG_PCI_STUB) += pci-stub.o
+
ifeq ($(CONFIG_PCI_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 39bb96b413ef..381444794778 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -66,6 +66,39 @@ EXPORT_SYMBOL(pci_bus_write_config_byte);
EXPORT_SYMBOL(pci_bus_write_config_word);
EXPORT_SYMBOL(pci_bus_write_config_dword);
+
+/**
+ * pci_read_vpd - Read one entry from Vital Product Data
+ * @dev: pci device struct
+ * @pos: offset in vpd space
+ * @count: number of bytes to read
+ * @buf: pointer to where to store result
+ *
+ */
+ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf)
+{
+ if (!dev->vpd || !dev->vpd->ops)
+ return -ENODEV;
+ return dev->vpd->ops->read(dev, pos, count, buf);
+}
+EXPORT_SYMBOL(pci_read_vpd);
+
+/**
+ * pci_write_vpd - Write entry to Vital Product Data
+ * @dev: pci device struct
+ * @pos: offset in vpd space
+ * @count: number of bytes to read
+ * @val: value to write
+ *
+ */
+ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf)
+{
+ if (!dev->vpd || !dev->vpd->ops)
+ return -ENODEV;
+ return dev->vpd->ops->write(dev, pos, count, buf);
+}
+EXPORT_SYMBOL(pci_write_vpd);
+
/*
* The following routines are to prevent the user from accessing PCI config
* space when it's unsafe to do so. Some devices require this during BIST and
@@ -133,125 +166,145 @@ PCI_USER_WRITE_CONFIG(dword, u32)
struct pci_vpd_pci22 {
struct pci_vpd base;
- spinlock_t lock; /* controls access to hardware and the flags */
- u8 cap;
+ struct mutex lock;
+ u16 flag;
bool busy;
- bool flag; /* value of F bit to wait for */
+ u8 cap;
};
-/* Wait for last operation to complete */
+/*
+ * Wait for last operation to complete.
+ * This code has to spin since there is no other notification from the PCI
+ * hardware. Since the VPD is often implemented by serial attachment to an
+ * EEPROM, it may take many milliseconds to complete.
+ */
static int pci_vpd_pci22_wait(struct pci_dev *dev)
{
struct pci_vpd_pci22 *vpd =
container_of(dev->vpd, struct pci_vpd_pci22, base);
- u16 flag, status;
- int wait;
+ unsigned long timeout = jiffies + HZ/20 + 2;
+ u16 status;
int ret;
if (!vpd->busy)
return 0;
- flag = vpd->flag ? PCI_VPD_ADDR_F : 0;
- wait = vpd->flag ? 10 : 1000; /* read: 100 us; write: 10 ms */
for (;;) {
- ret = pci_user_read_config_word(dev,
- vpd->cap + PCI_VPD_ADDR,
+ ret = pci_user_read_config_word(dev, vpd->cap + PCI_VPD_ADDR,
&status);
- if (ret < 0)
+ if (ret)
return ret;
- if ((status & PCI_VPD_ADDR_F) == flag) {
+
+ if ((status & PCI_VPD_ADDR_F) == vpd->flag) {
vpd->busy = false;
return 0;
}
- if (wait-- == 0)
+
+ if (time_after(jiffies, timeout))
return -ETIMEDOUT;
- udelay(10);
+ if (fatal_signal_pending(current))
+ return -EINTR;
+ if (!cond_resched())
+ udelay(10);
}
}
-static int pci_vpd_pci22_read(struct pci_dev *dev, int pos, int size,
- char *buf)
+static ssize_t pci_vpd_pci22_read(struct pci_dev *dev, loff_t pos, size_t count,
+ void *arg)
{
struct pci_vpd_pci22 *vpd =
container_of(dev->vpd, struct pci_vpd_pci22, base);
- u32 val;
int ret;
- int begin, end, i;
+ loff_t end = pos + count;
+ u8 *buf = arg;
- if (pos < 0 || pos > vpd->base.len || size > vpd->base.len - pos)
+ if (pos < 0 || pos > vpd->base.len || end > vpd->base.len)
return -EINVAL;
- if (size == 0)
- return 0;
- spin_lock_irq(&vpd->lock);
- ret = pci_vpd_pci22_wait(dev);
- if (ret < 0)
- goto out;
- ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
- pos & ~3);
- if (ret < 0)
- goto out;
- vpd->busy = true;
- vpd->flag = 1;
+ if (mutex_lock_killable(&vpd->lock))
+ return -EINTR;
+
ret = pci_vpd_pci22_wait(dev);
if (ret < 0)
goto out;
- ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA,
- &val);
-out:
- spin_unlock_irq(&vpd->lock);
- if (ret < 0)
- return ret;
-
- /* Convert to bytes */
- begin = pos & 3;
- end = min(4, begin + size);
- for (i = 0; i < end; ++i) {
- if (i >= begin)
- *buf++ = val;
- val >>= 8;
+
+ while (pos < end) {
+ u32 val;
+ unsigned int i, skip;
+
+ ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
+ pos & ~3);
+ if (ret < 0)
+ break;
+ vpd->busy = true;
+ vpd->flag = PCI_VPD_ADDR_F;
+ ret = pci_vpd_pci22_wait(dev);
+ if (ret < 0)
+ break;
+
+ ret = pci_user_read_config_dword(dev, vpd->cap + PCI_VPD_DATA, &val);
+ if (ret < 0)
+ break;
+
+ skip = pos & 3;
+ for (i = 0; i < sizeof(u32); i++) {
+ if (i >= skip) {
+ *buf++ = val;
+ if (++pos == end)
+ break;
+ }
+ val >>= 8;
+ }
}
- return end - begin;
+out:
+ mutex_unlock(&vpd->lock);
+ return ret ? ret : count;
}
-static int pci_vpd_pci22_write(struct pci_dev *dev, int pos, int size,
- const char *buf)
+static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count,
+ const void *arg)
{
struct pci_vpd_pci22 *vpd =
container_of(dev->vpd, struct pci_vpd_pci22, base);
- u32 val;
- int ret;
+ const u8 *buf = arg;
+ loff_t end = pos + count;
+ int ret = 0;
- if (pos < 0 || pos > vpd->base.len || pos & 3 ||
- size > vpd->base.len - pos || size < 4)
+ if (pos < 0 || (pos & 3) || (count & 3) || end > vpd->base.len)
return -EINVAL;
- val = (u8) *buf++;
- val |= ((u8) *buf++) << 8;
- val |= ((u8) *buf++) << 16;
- val |= ((u32)(u8) *buf++) << 24;
+ if (mutex_lock_killable(&vpd->lock))
+ return -EINTR;
- spin_lock_irq(&vpd->lock);
ret = pci_vpd_pci22_wait(dev);
if (ret < 0)
goto out;
- ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA,
- val);
- if (ret < 0)
- goto out;
- ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
- pos | PCI_VPD_ADDR_F);
- if (ret < 0)
- goto out;
- vpd->busy = true;
- vpd->flag = 0;
- ret = pci_vpd_pci22_wait(dev);
-out:
- spin_unlock_irq(&vpd->lock);
- if (ret < 0)
- return ret;
- return 4;
+ while (pos < end) {
+ u32 val;
+
+ val = *buf++;
+ val |= *buf++ << 8;
+ val |= *buf++ << 16;
+ val |= *buf++ << 24;
+
+ ret = pci_user_write_config_dword(dev, vpd->cap + PCI_VPD_DATA, val);
+ if (ret < 0)
+ break;
+ ret = pci_user_write_config_word(dev, vpd->cap + PCI_VPD_ADDR,
+ pos | PCI_VPD_ADDR_F);
+ if (ret < 0)
+ break;
+
+ vpd->busy = true;
+ vpd->flag = 0;
+ ret = pci_vpd_pci22_wait(dev);
+
+ pos += sizeof(u32);
+ }
+out:
+ mutex_unlock(&vpd->lock);
+ return ret ? ret : count;
}
static void pci_vpd_pci22_release(struct pci_dev *dev)
@@ -259,7 +312,7 @@ static void pci_vpd_pci22_release(struct pci_dev *dev)
kfree(container_of(dev->vpd, struct pci_vpd_pci22, base));
}
-static struct pci_vpd_ops pci_vpd_pci22_ops = {
+static const struct pci_vpd_ops pci_vpd_pci22_ops = {
.read = pci_vpd_pci22_read,
.write = pci_vpd_pci22_write,
.release = pci_vpd_pci22_release,
@@ -279,7 +332,7 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
vpd->base.len = PCI_VPD_PCI22_SIZE;
vpd->base.ops = &pci_vpd_pci22_ops;
- spin_lock_init(&vpd->lock);
+ mutex_init(&vpd->lock);
vpd->cap = cap;
vpd->busy = false;
dev->vpd = &vpd->base;
@@ -287,6 +340,29 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
}
/**
+ * pci_vpd_truncate - Set available Vital Product Data size
+ * @dev: pci device struct
+ * @size: available memory in bytes
+ *
+ * Adjust size of available VPD area.
+ */
+int pci_vpd_truncate(struct pci_dev *dev, size_t size)
+{
+ if (!dev->vpd)
+ return -EINVAL;
+
+ /* limited by the access method */
+ if (size > dev->vpd->len)
+ return -EINVAL;
+
+ dev->vpd->len = size;
+ dev->vpd->attr->size = size;
+
+ return 0;
+}
+EXPORT_SYMBOL(pci_vpd_truncate);
+
+/**
* pci_block_user_cfg_access - Block userspace PCI config reads/writes
* @dev: pci device struct
*
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 999cc4088b59..52b54f053be0 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -71,7 +71,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
}
/**
- * add a single device
+ * pci_bus_add_device - add a single device
* @dev: device to add
*
* This adds a single pci device to the global
@@ -91,6 +91,37 @@ int pci_bus_add_device(struct pci_dev *dev)
}
/**
+ * pci_bus_add_child - add a child bus
+ * @bus: bus to add
+ *
+ * This adds sysfs entries for a single bus
+ */
+int pci_bus_add_child(struct pci_bus *bus)
+{
+ int retval;
+
+ if (bus->bridge)
+ bus->dev.parent = bus->bridge;
+
+ retval = device_register(&bus->dev);
+ if (retval)
+ return retval;
+
+ bus->is_added = 1;
+
+ retval = device_create_file(&bus->dev, &dev_attr_cpuaffinity);
+ if (retval)
+ return retval;
+
+ retval = device_create_file(&bus->dev, &dev_attr_cpulistaffinity);
+
+ /* Create legacy_io and legacy_mem files for this bus */
+ pci_create_legacy_files(bus);
+
+ return retval;
+}
+
+/**
* pci_bus_add_devices - insert newly discovered PCI devices
* @bus: bus to check for new devices
*
@@ -105,7 +136,7 @@ int pci_bus_add_device(struct pci_dev *dev)
void pci_bus_add_devices(struct pci_bus *bus)
{
struct pci_dev *dev;
- struct pci_bus *child_bus;
+ struct pci_bus *child;
int retval;
list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -120,45 +151,29 @@ void pci_bus_add_devices(struct pci_bus *bus)
list_for_each_entry(dev, &bus->devices, bus_list) {
BUG_ON(!dev->is_added);
+ child = dev->subordinate;
/*
* If there is an unattached subordinate bus, attach
* it and then scan for unattached PCI devices.
*/
- if (dev->subordinate) {
- if (list_empty(&dev->subordinate->node)) {
- down_write(&pci_bus_sem);
- list_add_tail(&dev->subordinate->node,
- &dev->bus->children);
- up_write(&pci_bus_sem);
- }
- pci_bus_add_devices(dev->subordinate);
-
- /* register the bus with sysfs as the parent is now
- * properly registered. */
- child_bus = dev->subordinate;
- if (child_bus->is_added)
- continue;
- child_bus->dev.parent = child_bus->bridge;
- retval = device_register(&child_bus->dev);
- if (retval)
- dev_err(&dev->dev, "Error registering pci_bus,"
- " continuing...\n");
- else {
- child_bus->is_added = 1;
- retval = device_create_file(&child_bus->dev,
- &dev_attr_cpuaffinity);
- }
- if (retval)
- dev_err(&dev->dev, "Error creating cpuaffinity"
- " file, continuing...\n");
-
- retval = device_create_file(&child_bus->dev,
- &dev_attr_cpulistaffinity);
- if (retval)
- dev_err(&dev->dev,
- "Error creating cpulistaffinity"
- " file, continuing...\n");
+ if (!child)
+ continue;
+ if (list_empty(&child->node)) {
+ down_write(&pci_bus_sem);
+ list_add_tail(&child->node, &dev->bus->children);
+ up_write(&pci_bus_sem);
}
+ pci_bus_add_devices(child);
+
+ /*
+ * register the bus with sysfs as the parent is now
+ * properly registered.
+ */
+ if (child->is_added)
+ continue;
+ retval = pci_bus_add_child(child);
+ if (retval)
+ dev_err(&dev->dev, "Error adding bus, continuing\n");
}
}
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
index 9bdbe1a6688f..e31fb91652ce 100644
--- a/drivers/pci/hotplug/Makefile
+++ b/drivers/pci/hotplug/Makefile
@@ -55,6 +55,9 @@ pciehp-objs := pciehp_core.o \
pciehp_ctrl.o \
pciehp_pci.o \
pciehp_hpc.o
+ifdef CONFIG_ACPI
+pciehp-objs += pciehp_acpi.o
+endif
shpchp-objs := shpchp_core.o \
shpchp_ctrl.o \
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c
index e17ef54f0efc..1c1141801060 100644
--- a/drivers/pci/hotplug/acpi_pcihp.c
+++ b/drivers/pci/hotplug/acpi_pcihp.c
@@ -33,7 +33,6 @@
#include <linux/pci-acpi.h>
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
-#include <acpi/actypes.h>
#define MY_NAME "acpi_pcihp"
@@ -501,5 +500,74 @@ int acpi_root_bridge(acpi_handle handle)
}
EXPORT_SYMBOL_GPL(acpi_root_bridge);
+
+static int is_ejectable(acpi_handle handle)
+{
+ acpi_status status;
+ acpi_handle tmp;
+ unsigned long long removable;
+ status = acpi_get_handle(handle, "_ADR", &tmp);
+ if (ACPI_FAILURE(status))
+ return 0;
+ status = acpi_get_handle(handle, "_EJ0", &tmp);
+ if (ACPI_SUCCESS(status))
+ return 1;
+ status = acpi_evaluate_integer(handle, "_RMV", NULL, &removable);
+ if (ACPI_SUCCESS(status) && removable)
+ return 1;
+ return 0;
+}
+
+/**
+ * acpi_pcihp_check_ejectable - check if handle is ejectable ACPI PCI slot
+ * @pbus: the PCI bus of the PCI slot corresponding to 'handle'
+ * @handle: ACPI handle to check
+ *
+ * Return 1 if handle is ejectable PCI slot, 0 otherwise.
+ */
+int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle)
+{
+ acpi_handle bridge_handle, parent_handle;
+
+ if (!(bridge_handle = acpi_pci_get_bridge_handle(pbus)))
+ return 0;
+ if ((ACPI_FAILURE(acpi_get_parent(handle, &parent_handle))))
+ return 0;
+ if (bridge_handle != parent_handle)
+ return 0;
+ return is_ejectable(handle);
+}
+EXPORT_SYMBOL_GPL(acpi_pci_check_ejectable);
+
+static acpi_status
+check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ int *found = (int *)context;
+ if (is_ejectable(handle)) {
+ *found = 1;
+ return AE_CTRL_TERMINATE;
+ }
+ return AE_OK;
+}
+
+/**
+ * acpi_pci_detect_ejectable - check if the PCI bus has ejectable slots
+ * @pbus - PCI bus to scan
+ *
+ * Returns 1 if the PCI bus has ACPI based ejectable slots, 0 otherwise.
+ */
+int acpi_pci_detect_ejectable(struct pci_bus *pbus)
+{
+ acpi_handle handle;
+ int found = 0;
+
+ if (!(handle = acpi_pci_get_bridge_handle(pbus)))
+ return 0;
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
+ check_hotplug, (void *)&found, NULL);
+ return found;
+}
+EXPORT_SYMBOL_GPL(acpi_pci_detect_ejectable);
+
module_param(debug_acpi, bool, 0644);
MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not");
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 9bcb6cbd5aa9..4fc168b70095 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -44,7 +44,7 @@
do { \
if (acpiphp_debug) \
printk(KERN_DEBUG "%s: " format, \
- MY_NAME , ## arg); \
+ MY_NAME , ## arg); \
} while (0)
#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 3affc6472e65..803d9ddd6e75 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -46,6 +46,7 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
+#include <linux/pci-acpi.h>
#include <linux/mutex.h>
#include "../pci.h"
@@ -62,61 +63,6 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus);
static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
-
-/*
- * initialization & terminatation routines
- */
-
-/**
- * is_ejectable - determine if a slot is ejectable
- * @handle: handle to acpi namespace
- *
- * Ejectable slot should satisfy at least these conditions:
- *
- * 1. has _ADR method
- * 2. has _EJ0 method
- *
- * optionally
- *
- * 1. has _STA method
- * 2. has _PS0 method
- * 3. has _PS3 method
- * 4. ..
- */
-static int is_ejectable(acpi_handle handle)
-{
- acpi_status status;
- acpi_handle tmp;
-
- status = acpi_get_handle(handle, "_ADR", &tmp);
- if (ACPI_FAILURE(status)) {
- return 0;
- }
-
- status = acpi_get_handle(handle, "_EJ0", &tmp);
- if (ACPI_FAILURE(status)) {
- return 0;
- }
-
- return 1;
-}
-
-
-/* callback routine to check for the existence of ejectable slots */
-static acpi_status
-is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- int *count = (int *)context;
-
- if (is_ejectable(handle)) {
- (*count)++;
- /* only one ejectable slot is enough */
- return AE_CTRL_TERMINATE;
- } else {
- return AE_OK;
- }
-}
-
/* callback routine to check for the existence of a pci dock device */
static acpi_status
is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
@@ -131,9 +77,6 @@ is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
}
}
-
-
-
/*
* the _DCK method can do funny things... and sometimes not
* hah-hah funny.
@@ -160,9 +103,9 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
if (((buses >> 8) & 0xff) != bus->secondary) {
buses = (buses & 0xff000000)
- | ((unsigned int)(bus->primary) << 0)
- | ((unsigned int)(bus->secondary) << 8)
- | ((unsigned int)(bus->subordinate) << 16);
+ | ((unsigned int)(bus->primary) << 0)
+ | ((unsigned int)(bus->secondary) << 8)
+ | ((unsigned int)(bus->subordinate) << 16);
pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
}
return NOTIFY_OK;
@@ -184,17 +127,12 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
acpi_status status = AE_OK;
unsigned long long adr, sun;
int device, function, retval;
+ struct pci_bus *pbus = bridge->pci_bus;
- status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
-
- if (ACPI_FAILURE(status))
- return AE_OK;
-
- status = acpi_get_handle(handle, "_EJ0", &tmp);
-
- if (ACPI_FAILURE(status) && !(is_dock_device(handle)))
+ if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle))
return AE_OK;
+ acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
device = (adr >> 16) & 0xffff;
function = adr & 0xffff;
@@ -205,7 +143,8 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
INIT_LIST_HEAD(&newfunc->sibling);
newfunc->handle = handle;
newfunc->function = function;
- if (ACPI_SUCCESS(status))
+
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
newfunc->flags = FUNC_HAS_EJ0;
if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp)))
@@ -256,8 +195,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
bridge->nr_slots++;
dbg("found ACPI PCI Hotplug slot %llu at PCI %04x:%02x:%02x\n",
- slot->sun, pci_domain_nr(bridge->pci_bus),
- bridge->pci_bus->number, slot->device);
+ slot->sun, pci_domain_nr(pbus), pbus->number, device);
retval = acpiphp_register_hotplug_slot(slot);
if (retval) {
if (retval == -EBUSY)
@@ -274,8 +212,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
list_add_tail(&newfunc->sibling, &slot->funcs);
/* associate corresponding pci_dev */
- newfunc->pci_dev = pci_get_slot(bridge->pci_bus,
- PCI_DEVFN(device, function));
+ newfunc->pci_dev = pci_get_slot(pbus, PCI_DEVFN(device, function));
if (newfunc->pci_dev) {
slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
}
@@ -324,27 +261,17 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
/* see if it's worth looking at this bridge */
-static int detect_ejectable_slots(acpi_handle *bridge_handle)
+static int detect_ejectable_slots(struct pci_bus *pbus)
{
- acpi_status status;
- int count;
-
- count = 0;
-
- /* only check slots defined directly below bridge object */
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
- is_ejectable_slot, (void *)&count, NULL);
-
- /*
- * we also need to add this bridge if there is a dock bridge or
- * other pci device on a dock station (removable)
- */
- if (!count)
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle,
- (u32)1, is_pci_dock_device, (void *)&count,
- NULL);
-
- return count;
+ int found = acpi_pci_detect_ejectable(pbus);
+ if (!found) {
+ acpi_handle bridge_handle = acpi_pci_get_bridge_handle(pbus);
+ if (!bridge_handle)
+ return 0;
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
+ is_pci_dock_device, (void *)&found, NULL);
+ }
+ return found;
}
@@ -554,7 +481,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
goto out;
/* check if this bridge has ejectable slots */
- if ((detect_ejectable_slots(handle) > 0)) {
+ if ((detect_ejectable_slots(dev->subordinate) > 0)) {
dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
add_p2p_bridge(handle, dev);
}
@@ -615,7 +542,7 @@ static int add_bridge(acpi_handle handle)
}
/* check if this bridge has ejectable slots */
- if (detect_ejectable_slots(handle) > 0) {
+ if (detect_ejectable_slots(pci_bus) > 0) {
dbg("found PCI host-bus bridge with hot-pluggable slots\n");
add_host_bridge(handle, pci_bus);
}
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index 881fdd2b7313..5befa7e379b7 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -271,7 +271,7 @@ static void ibm_handle_events(acpi_handle handle, u32 event, void *context)
dbg("%s: generationg bus event\n", __func__);
acpi_bus_generate_proc_event(note->device, note->event, detail);
acpi_bus_generate_netlink_event(note->device->pnp.device_class,
- note->device->dev.bus_id,
+ dev_name(&note->device->dev),
note->event, detail);
} else
note->event = event;
diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
index a60a25290995..cc227a8c4b11 100644
--- a/drivers/pci/hotplug/cpqphp_ctrl.c
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c
@@ -1954,7 +1954,7 @@ void cpqhp_pushbutton_thread(unsigned long slot)
return ;
}
- if (func != NULL && ctrl != NULL) {
+ if (ctrl != NULL) {
if (cpqhp_process_SI(ctrl, func) != 0) {
amber_LED_on(ctrl, hp_slot);
green_LED_off(ctrl, hp_slot);
@@ -2604,7 +2604,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
for (cloop = 0; cloop < 4; cloop++) {
if (irqs.valid_INT & (0x01 << cloop)) {
rc = cpqhp_set_irq(func->bus, func->device,
- 0x0A + cloop, irqs.interrupt[cloop]);
+ cloop + 1, irqs.interrupt[cloop]);
if (rc)
goto free_and_out;
}
@@ -2945,7 +2945,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func
}
if (!behind_bridge) {
- rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ);
+ rc = cpqhp_set_irq(func->bus, func->device, temp_byte, IRQ);
if (rc)
return 1;
} else {
diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
index df146be9d2e9..6c0ed0fcb8ee 100644
--- a/drivers/pci/hotplug/cpqphp_pci.c
+++ b/drivers/pci/hotplug/cpqphp_pci.c
@@ -171,7 +171,7 @@ int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
fakebus->number = bus_num;
dbg("%s: dev %d, bus %d, pin %d, num %d\n",
__func__, dev_num, bus_num, int_pin, irq_num);
- rc = pcibios_set_irq_routing(fakedev, int_pin - 0x0a, irq_num);
+ rc = pcibios_set_irq_routing(fakedev, int_pin - 1, irq_num);
kfree(fakedev);
kfree(fakebus);
dbg("%s: rc %d\n", __func__, rc);
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
index 3a2637a00934..b0e7de9e536d 100644
--- a/drivers/pci/hotplug/fakephp.c
+++ b/drivers/pci/hotplug/fakephp.c
@@ -324,6 +324,7 @@ static int disable_slot(struct hotplug_slot *slot)
if (test_and_set_bit(0, &dslot->removed)) {
dbg("Slot already scheduled for removal\n");
+ pci_dev_put(dev);
return -ENODEV;
}
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index b2801a7ee37f..db85284ffb62 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -217,14 +217,25 @@ struct hpc_ops {
#ifdef CONFIG_ACPI
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
-#include <acpi/actypes.h>
#include <linux/pci-acpi.h>
+extern void __init pciehp_acpi_slot_detection_init(void);
+extern int pciehp_acpi_slot_detection_check(struct pci_dev *dev);
+
+static inline void pciehp_firmware_init(void)
+{
+ pciehp_acpi_slot_detection_init();
+}
+
static inline int pciehp_get_hp_hw_control_from_firmware(struct pci_dev *dev)
{
+ int retval;
u32 flags = (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL |
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
- return acpi_get_hp_hw_control_from_firmware(dev, flags);
+ retval = acpi_get_hp_hw_control_from_firmware(dev, flags);
+ if (retval)
+ return retval;
+ return pciehp_acpi_slot_detection_check(dev);
}
static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
@@ -235,6 +246,7 @@ static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
return 0;
}
#else
+#define pciehp_firmware_init() do {} while (0)
#define pciehp_get_hp_hw_control_from_firmware(dev) 0
#define pciehp_get_hp_params_from_firmware(dev, hpp) (-ENODEV)
#endif /* CONFIG_ACPI */
diff --git a/drivers/pci/hotplug/pciehp_acpi.c b/drivers/pci/hotplug/pciehp_acpi.c
new file mode 100644
index 000000000000..438d795f9fe3
--- /dev/null
+++ b/drivers/pci/hotplug/pciehp_acpi.c
@@ -0,0 +1,141 @@
+/*
+ * ACPI related functions for PCI Express Hot Plug driver.
+ *
+ * Copyright (C) 2008 Kenji Kaneshige
+ * Copyright (C) 2008 Fujitsu Limited.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT. 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/acpi.h>
+#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
+#include "pciehp.h"
+
+#define PCIEHP_DETECT_PCIE (0)
+#define PCIEHP_DETECT_ACPI (1)
+#define PCIEHP_DETECT_AUTO (2)
+#define PCIEHP_DETECT_DEFAULT PCIEHP_DETECT_AUTO
+
+static int slot_detection_mode;
+static char *pciehp_detect_mode;
+module_param(pciehp_detect_mode, charp, 0444);
+MODULE_PARM_DESC(pciehp_detect_mode,
+ "Slot detection mode: pcie, acpi, auto\n"
+ " pcie - Use PCIe based slot detection\n"
+ " acpi - Use ACPI for slot detection\n"
+ " auto(default) - Auto select mode. Use acpi option if duplicate\n"
+ " slot ids are found. Otherwise, use pcie option\n");
+
+int pciehp_acpi_slot_detection_check(struct pci_dev *dev)
+{
+ if (slot_detection_mode != PCIEHP_DETECT_ACPI)
+ return 0;
+ if (acpi_pci_detect_ejectable(dev->subordinate))
+ return 0;
+ return -ENODEV;
+}
+
+static int __init parse_detect_mode(void)
+{
+ if (!pciehp_detect_mode)
+ return PCIEHP_DETECT_DEFAULT;
+ if (!strcmp(pciehp_detect_mode, "pcie"))
+ return PCIEHP_DETECT_PCIE;
+ if (!strcmp(pciehp_detect_mode, "acpi"))
+ return PCIEHP_DETECT_ACPI;
+ if (!strcmp(pciehp_detect_mode, "auto"))
+ return PCIEHP_DETECT_AUTO;
+ warn("bad specifier '%s' for pciehp_detect_mode. Use default\n",
+ pciehp_detect_mode);
+ return PCIEHP_DETECT_DEFAULT;
+}
+
+static struct pcie_port_service_id __initdata port_pci_ids[] = {
+ {
+ .vendor = PCI_ANY_ID,
+ .device = PCI_ANY_ID,
+ .port_type = PCIE_ANY_PORT,
+ .service_type = PCIE_PORT_SERVICE_HP,
+ .driver_data = 0,
+ }, { /* end: all zeroes */ }
+};
+
+static int __initdata dup_slot_id;
+static int __initdata acpi_slot_detected;
+static struct list_head __initdata dummy_slots = LIST_HEAD_INIT(dummy_slots);
+
+/* Dummy driver for dumplicate name detection */
+static int __init dummy_probe(struct pcie_device *dev,
+ const struct pcie_port_service_id *id)
+{
+ int pos;
+ u32 slot_cap;
+ struct slot *slot, *tmp;
+ struct pci_dev *pdev = dev->port;
+ struct pci_bus *pbus = pdev->subordinate;
+ if (!(slot = kzalloc(sizeof(*slot), GFP_KERNEL)))
+ return -ENOMEM;
+ /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */
+ if (pciehp_get_hp_hw_control_from_firmware(pdev))
+ return -ENODEV;
+ if (!(pos = pci_find_capability(pdev, PCI_CAP_ID_EXP)))
+ return -ENODEV;
+ pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &slot_cap);
+ slot->number = slot_cap >> 19;
+ list_for_each_entry(tmp, &dummy_slots, slot_list) {
+ if (tmp->number == slot->number)
+ dup_slot_id++;
+ }
+ list_add_tail(&slot->slot_list, &dummy_slots);
+ if (!acpi_slot_detected && acpi_pci_detect_ejectable(pbus))
+ acpi_slot_detected = 1;
+ return -ENODEV; /* dummy driver always returns error */
+}
+
+static struct pcie_port_service_driver __initdata dummy_driver = {
+ .name = "pciehp_dummy",
+ .id_table = port_pci_ids,
+ .probe = dummy_probe,
+};
+
+static int __init select_detection_mode(void)
+{
+ struct slot *slot, *tmp;
+ pcie_port_service_register(&dummy_driver);
+ pcie_port_service_unregister(&dummy_driver);
+ list_for_each_entry_safe(slot, tmp, &dummy_slots, slot_list) {
+ list_del(&slot->slot_list);
+ kfree(slot);
+ }
+ if (acpi_slot_detected && dup_slot_id)
+ return PCIEHP_DETECT_ACPI;
+ return PCIEHP_DETECT_PCIE;
+}
+
+void __init pciehp_acpi_slot_detection_init(void)
+{
+ slot_detection_mode = parse_detect_mode();
+ if (slot_detection_mode != PCIEHP_DETECT_AUTO)
+ goto out;
+ slot_detection_mode = select_detection_mode();
+out:
+ if (slot_detection_mode == PCIEHP_DETECT_ACPI)
+ info("Using ACPI for slot detection.\n");
+}
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 39cf248d24e3..5482d4ed8256 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -522,6 +522,7 @@ static int __init pcied_init(void)
{
int retval = 0;
+ pciehp_firmware_init();
retval = pcie_port_service_register(&hpdriver_portdrv);
dbg("pcie_port_service_register = %d\n", retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index fead63c6b49e..ff4034502d24 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -178,15 +178,14 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
"Issue of Slot Power Off command failed\n");
return;
}
+ /*
+ * After turning power off, we must wait for at least 1 second
+ * before taking any action that relies on power having been
+ * removed from the slot/adapter.
+ */
+ msleep(1000);
}
- /*
- * After turning power off, we must wait for at least 1 second
- * before taking any action that relies on power having been
- * removed from the slot/adapter.
- */
- msleep(1000);
-
if (PWR_LED(ctrl))
pslot->hpc_ops->green_led_off(pslot);
@@ -286,15 +285,14 @@ static int remove_board(struct slot *p_slot)
"Issue of Slot Disable command failed\n");
return retval;
}
+ /*
+ * After turning power off, we must wait for at least 1 second
+ * before taking any action that relies on power having been
+ * removed from the slot/adapter.
+ */
+ msleep(1000);
}
- /*
- * After turning power off, we must wait for at least 1 second
- * before taking any action that relies on power having been
- * removed from the slot/adapter.
- */
- msleep(1000);
-
if (PWR_LED(ctrl))
/* turn off Green LED */
p_slot->hpc_ops->green_led_off(p_slot);
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index b643ca13e4f1..71a8012886b0 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -42,42 +42,6 @@
static atomic_t pciehp_num_controllers = ATOMIC_INIT(0);
-struct ctrl_reg {
- u8 cap_id;
- u8 nxt_ptr;
- u16 cap_reg;
- u32 dev_cap;
- u16 dev_ctrl;
- u16 dev_status;
- u32 lnk_cap;
- u16 lnk_ctrl;
- u16 lnk_status;
- u32 slot_cap;
- u16 slot_ctrl;
- u16 slot_status;
- u16 root_ctrl;
- u16 rsvp;
- u32 root_status;
-} __attribute__ ((packed));
-
-/* offsets to the controller registers based on the above structure layout */
-enum ctrl_offsets {
- PCIECAPID = offsetof(struct ctrl_reg, cap_id),
- NXTCAPPTR = offsetof(struct ctrl_reg, nxt_ptr),
- CAPREG = offsetof(struct ctrl_reg, cap_reg),
- DEVCAP = offsetof(struct ctrl_reg, dev_cap),
- DEVCTRL = offsetof(struct ctrl_reg, dev_ctrl),
- DEVSTATUS = offsetof(struct ctrl_reg, dev_status),
- LNKCAP = offsetof(struct ctrl_reg, lnk_cap),
- LNKCTRL = offsetof(struct ctrl_reg, lnk_ctrl),
- LNKSTATUS = offsetof(struct ctrl_reg, lnk_status),
- SLOTCAP = offsetof(struct ctrl_reg, slot_cap),
- SLOTCTRL = offsetof(struct ctrl_reg, slot_ctrl),
- SLOTSTATUS = offsetof(struct ctrl_reg, slot_status),
- ROOTCTRL = offsetof(struct ctrl_reg, root_ctrl),
- ROOTSTATUS = offsetof(struct ctrl_reg, root_status),
-};
-
static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value)
{
struct pci_dev *dev = ctrl->pci_dev;
@@ -102,95 +66,9 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
return pci_write_config_dword(dev, ctrl->cap_base + reg, value);
}
-/* Field definitions in PCI Express Capabilities Register */
-#define CAP_VER 0x000F
-#define DEV_PORT_TYPE 0x00F0
-#define SLOT_IMPL 0x0100
-#define MSG_NUM 0x3E00
-
-/* Device or Port Type */
-#define NAT_ENDPT 0x00
-#define LEG_ENDPT 0x01
-#define ROOT_PORT 0x04
-#define UP_STREAM 0x05
-#define DN_STREAM 0x06
-#define PCIE_PCI_BRDG 0x07
-#define PCI_PCIE_BRDG 0x10
-
-/* Field definitions in Device Capabilities Register */
-#define DATTN_BUTTN_PRSN 0x1000
-#define DATTN_LED_PRSN 0x2000
-#define DPWR_LED_PRSN 0x4000
-
-/* Field definitions in Link Capabilities Register */
-#define MAX_LNK_SPEED 0x000F
-#define MAX_LNK_WIDTH 0x03F0
-#define LINK_ACTIVE_REPORTING 0x00100000
-
-/* Link Width Encoding */
-#define LNK_X1 0x01
-#define LNK_X2 0x02
-#define LNK_X4 0x04
-#define LNK_X8 0x08
-#define LNK_X12 0x0C
-#define LNK_X16 0x10
-#define LNK_X32 0x20
-
-/*Field definitions of Link Status Register */
-#define LNK_SPEED 0x000F
-#define NEG_LINK_WD 0x03F0
-#define LNK_TRN_ERR 0x0400
-#define LNK_TRN 0x0800
-#define SLOT_CLK_CONF 0x1000
-#define LINK_ACTIVE 0x2000
-
-/* Field definitions in Slot Capabilities Register */
-#define ATTN_BUTTN_PRSN 0x00000001
-#define PWR_CTRL_PRSN 0x00000002
-#define MRL_SENS_PRSN 0x00000004
-#define ATTN_LED_PRSN 0x00000008
-#define PWR_LED_PRSN 0x00000010
-#define HP_SUPR_RM_SUP 0x00000020
-#define HP_CAP 0x00000040
-#define SLOT_PWR_VALUE 0x000003F8
-#define SLOT_PWR_LIMIT 0x00000C00
-#define PSN 0xFFF80000 /* PSN: Physical Slot Number */
-
-/* Field definitions in Slot Control Register */
-#define ATTN_BUTTN_ENABLE 0x0001
-#define PWR_FAULT_DETECT_ENABLE 0x0002
-#define MRL_DETECT_ENABLE 0x0004
-#define PRSN_DETECT_ENABLE 0x0008
-#define CMD_CMPL_INTR_ENABLE 0x0010
-#define HP_INTR_ENABLE 0x0020
-#define ATTN_LED_CTRL 0x00C0
-#define PWR_LED_CTRL 0x0300
-#define PWR_CTRL 0x0400
-#define EMI_CTRL 0x0800
-
-/* Attention indicator and Power indicator states */
-#define LED_ON 0x01
-#define LED_BLINK 0x10
-#define LED_OFF 0x11
-
/* Power Control Command */
#define POWER_ON 0
-#define POWER_OFF 0x0400
-
-/* EMI Status defines */
-#define EMI_DISENGAGED 0
-#define EMI_ENGAGED 1
-
-/* Field definitions in Slot Status Register */
-#define ATTN_BUTTN_PRESSED 0x0001
-#define PWR_FAULT_DETECTED 0x0002
-#define MRL_SENS_CHANGED 0x0004
-#define PRSN_DETECT_CHANGED 0x0008
-#define CMD_COMPLETED 0x0010
-#define MRL_STATE 0x0020
-#define PRSN_STATE 0x0040
-#define EMI_STATE 0x0080
-#define EMI_STATUS_BIT 7
+#define POWER_OFF PCI_EXP_SLTCTL_PCC
static irqreturn_t pcie_isr(int irq, void *dev_id);
static void start_int_poll_timer(struct controller *ctrl, int sec);
@@ -253,22 +131,20 @@ static inline void pciehp_free_irq(struct controller *ctrl)
static int pcie_poll_cmd(struct controller *ctrl)
{
u16 slot_status;
- int timeout = 1000;
+ int err, timeout = 1000;
- if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) {
- if (slot_status & CMD_COMPLETED) {
- pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED);
- return 1;
- }
+ err = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status);
+ if (!err && (slot_status & PCI_EXP_SLTSTA_CC)) {
+ pciehp_writew(ctrl, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_CC);
+ return 1;
}
while (timeout > 0) {
msleep(10);
timeout -= 10;
- if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status)) {
- if (slot_status & CMD_COMPLETED) {
- pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED);
- return 1;
- }
+ err = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status);
+ if (!err && (slot_status & PCI_EXP_SLTSTA_CC)) {
+ pciehp_writew(ctrl, PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_CC);
+ return 1;
}
}
return 0; /* timeout */
@@ -302,14 +178,14 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
mutex_lock(&ctrl->ctrl_lock);
- retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n",
__func__);
goto out;
}
- if (slot_status & CMD_COMPLETED) {
+ if (slot_status & PCI_EXP_SLTSTA_CC) {
if (!ctrl->no_cmd_complete) {
/*
* After 1 sec and CMD_COMPLETED still not set, just
@@ -332,7 +208,7 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
}
}
- retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
+ retval = pciehp_readw(ctrl, PCI_EXP_SLTCTL, &slot_ctrl);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__);
goto out;
@@ -342,7 +218,7 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
slot_ctrl |= (cmd & mask);
ctrl->cmd_busy = 1;
smp_mb();
- retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl);
+ retval = pciehp_writew(ctrl, PCI_EXP_SLTCTL, slot_ctrl);
if (retval)
ctrl_err(ctrl, "Cannot write to SLOTCTRL register\n");
@@ -356,8 +232,8 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
* completed interrupt is not enabled, we need to poll
* command completed event.
*/
- if (!(slot_ctrl & HP_INTR_ENABLE) ||
- !(slot_ctrl & CMD_CMPL_INTR_ENABLE))
+ if (!(slot_ctrl & PCI_EXP_SLTCTL_HPIE) ||
+ !(slot_ctrl & PCI_EXP_SLTCTL_CCIE))
poll = 1;
pcie_wait_cmd(ctrl, poll);
}
@@ -370,9 +246,9 @@ static inline int check_link_active(struct controller *ctrl)
{
u16 link_status;
- if (pciehp_readw(ctrl, LNKSTATUS, &link_status))
+ if (pciehp_readw(ctrl, PCI_EXP_LNKSTA, &link_status))
return 0;
- return !!(link_status & LINK_ACTIVE);
+ return !!(link_status & PCI_EXP_LNKSTA_DLLLA);
}
static void pcie_wait_link_active(struct controller *ctrl)
@@ -412,15 +288,15 @@ static int hpc_check_lnk_status(struct controller *ctrl)
} else
msleep(1000);
- retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
+ retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status);
if (retval) {
ctrl_err(ctrl, "Cannot read LNKSTATUS register\n");
return retval;
}
ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status);
- if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) ||
- !(lnk_status & NEG_LINK_WD)) {
+ if ((lnk_status & PCI_EXP_LNKSTA_LT) ||
+ !(lnk_status & PCI_EXP_LNKSTA_NLW)) {
ctrl_err(ctrl, "Link Training Error occurs \n");
retval = -1;
return retval;
@@ -436,16 +312,16 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
u8 atten_led_state;
int retval = 0;
- retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
+ retval = pciehp_readw(ctrl, PCI_EXP_SLTCTL, &slot_ctrl);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__);
return retval;
}
ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
+ __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_ctrl);
- atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;
+ atten_led_state = (slot_ctrl & PCI_EXP_SLTCTL_AIC) >> 6;
switch (atten_led_state) {
case 0:
@@ -475,15 +351,15 @@ static int hpc_get_power_status(struct slot *slot, u8 *status)
u8 pwr_state;
int retval = 0;
- retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
+ retval = pciehp_readw(ctrl, PCI_EXP_SLTCTL, &slot_ctrl);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__);
return retval;
}
ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
+ __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_ctrl);
- pwr_state = (slot_ctrl & PWR_CTRL) >> 10;
+ pwr_state = (slot_ctrl & PCI_EXP_SLTCTL_PCC) >> 10;
switch (pwr_state) {
case 0:
@@ -504,17 +380,15 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
u16 slot_status;
- int retval = 0;
+ int retval;
- retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n",
__func__);
return retval;
}
-
- *status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;
-
+ *status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS);
return 0;
}
@@ -522,18 +396,15 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
u16 slot_status;
- u8 card_state;
- int retval = 0;
+ int retval;
- retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n",
__func__);
return retval;
}
- card_state = (u8)((slot_status & PRSN_STATE) >> 6);
- *status = (card_state == 1) ? 1 : 0;
-
+ *status = !!(slot_status & PCI_EXP_SLTSTA_PDS);
return 0;
}
@@ -541,32 +412,28 @@ static int hpc_query_power_fault(struct slot *slot)
{
struct controller *ctrl = slot->ctrl;
u16 slot_status;
- u8 pwr_fault;
- int retval = 0;
+ int retval;
- retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status);
if (retval) {
ctrl_err(ctrl, "Cannot check for power fault\n");
return retval;
}
- pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
-
- return pwr_fault;
+ return !!(slot_status & PCI_EXP_SLTSTA_PFD);
}
static int hpc_get_emi_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
u16 slot_status;
- int retval = 0;
+ int retval;
- retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status);
if (retval) {
ctrl_err(ctrl, "Cannot check EMI status\n");
return retval;
}
- *status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
-
+ *status = !!(slot_status & PCI_EXP_SLTSTA_EIS);
return retval;
}
@@ -576,8 +443,8 @@ static int hpc_toggle_emi(struct slot *slot)
u16 cmd_mask;
int rc;
- slot_cmd = EMI_CTRL;
- cmd_mask = EMI_CTRL;
+ slot_cmd = PCI_EXP_SLTCTL_EIC;
+ cmd_mask = PCI_EXP_SLTCTL_EIC;
rc = pcie_write_cmd(slot->ctrl, slot_cmd, cmd_mask);
slot->last_emi_toggle = get_seconds();
@@ -591,7 +458,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
u16 cmd_mask;
int rc;
- cmd_mask = ATTN_LED_CTRL;
+ cmd_mask = PCI_EXP_SLTCTL_AIC;
switch (value) {
case 0 : /* turn off */
slot_cmd = 0x00C0;
@@ -607,7 +474,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
}
rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd);
return rc;
}
@@ -619,10 +486,10 @@ static void hpc_set_green_led_on(struct slot *slot)
u16 cmd_mask;
slot_cmd = 0x0100;
- cmd_mask = PWR_LED_CTRL;
+ cmd_mask = PCI_EXP_SLTCTL_PIC;
pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd);
}
static void hpc_set_green_led_off(struct slot *slot)
@@ -632,10 +499,10 @@ static void hpc_set_green_led_off(struct slot *slot)
u16 cmd_mask;
slot_cmd = 0x0300;
- cmd_mask = PWR_LED_CTRL;
+ cmd_mask = PCI_EXP_SLTCTL_PIC;
pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd);
}
static void hpc_set_green_led_blink(struct slot *slot)
@@ -645,10 +512,10 @@ static void hpc_set_green_led_blink(struct slot *slot)
u16 cmd_mask;
slot_cmd = 0x0200;
- cmd_mask = PWR_LED_CTRL;
+ cmd_mask = PCI_EXP_SLTCTL_PIC;
pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd);
}
static int hpc_power_on_slot(struct slot * slot)
@@ -662,15 +529,15 @@ static int hpc_power_on_slot(struct slot * slot)
ctrl_dbg(ctrl, "%s: slot->hp_slot %x\n", __func__, slot->hp_slot);
/* Clear sticky power-fault bit from previous power failures */
- retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ retval = pciehp_readw(ctrl, PCI_EXP_SLTSTA, &slot_status);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS register\n",
__func__);
return retval;
}
- slot_status &= PWR_FAULT_DETECTED;
+ slot_status &= PCI_EXP_SLTSTA_PFD;
if (slot_status) {
- retval = pciehp_writew(ctrl, SLOTSTATUS, slot_status);
+ retval = pciehp_writew(ctrl, PCI_EXP_SLTSTA, slot_status);
if (retval) {
ctrl_err(ctrl,
"%s: Cannot write to SLOTSTATUS register\n",
@@ -680,13 +547,13 @@ static int hpc_power_on_slot(struct slot * slot)
}
slot_cmd = POWER_ON;
- cmd_mask = PWR_CTRL;
+ cmd_mask = PCI_EXP_SLTCTL_PCC;
/* Enable detection that we turned off at slot power-off time */
if (!pciehp_poll_mode) {
- slot_cmd |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
- PRSN_DETECT_ENABLE);
- cmd_mask |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
- PRSN_DETECT_ENABLE);
+ slot_cmd |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE |
+ PCI_EXP_SLTCTL_PDCE);
+ cmd_mask |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE |
+ PCI_EXP_SLTCTL_PDCE);
}
retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
@@ -696,7 +563,7 @@ static int hpc_power_on_slot(struct slot * slot)
return -1;
}
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd);
return retval;
}
@@ -753,7 +620,7 @@ static int hpc_power_off_slot(struct slot * slot)
changed = pcie_mask_bad_dllp(ctrl);
slot_cmd = POWER_OFF;
- cmd_mask = PWR_CTRL;
+ cmd_mask = PCI_EXP_SLTCTL_PCC;
/*
* If we get MRL or presence detect interrupts now, the isr
* will notice the sticky power-fault bit too and issue power
@@ -762,10 +629,10 @@ static int hpc_power_off_slot(struct slot * slot)
* till the slot is powered on again.
*/
if (!pciehp_poll_mode) {
- slot_cmd &= ~(PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
- PRSN_DETECT_ENABLE);
- cmd_mask |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
- PRSN_DETECT_ENABLE);
+ slot_cmd &= ~(PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE |
+ PCI_EXP_SLTCTL_PDCE);
+ cmd_mask |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE |
+ PCI_EXP_SLTCTL_PDCE);
}
retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
@@ -775,7 +642,7 @@ static int hpc_power_off_slot(struct slot * slot)
goto out;
}
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
+ __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd);
out:
if (changed)
pcie_unmask_bad_dllp(ctrl);
@@ -796,19 +663,19 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
*/
intr_loc = 0;
do {
- if (pciehp_readw(ctrl, SLOTSTATUS, &detected)) {
+ if (pciehp_readw(ctrl, PCI_EXP_SLTSTA, &detected)) {
ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS\n",
__func__);
return IRQ_NONE;
}
- detected &= (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED |
- MRL_SENS_CHANGED | PRSN_DETECT_CHANGED |
- CMD_COMPLETED);
+ detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
+ PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
+ PCI_EXP_SLTSTA_CC);
intr_loc |= detected;
if (!intr_loc)
return IRQ_NONE;
- if (detected && pciehp_writew(ctrl, SLOTSTATUS, detected)) {
+ if (detected && pciehp_writew(ctrl, PCI_EXP_SLTSTA, detected)) {
ctrl_err(ctrl, "%s: Cannot write to SLOTSTATUS\n",
__func__);
return IRQ_NONE;
@@ -818,31 +685,31 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
ctrl_dbg(ctrl, "%s: intr_loc %x\n", __func__, intr_loc);
/* Check Command Complete Interrupt Pending */
- if (intr_loc & CMD_COMPLETED) {
+ if (intr_loc & PCI_EXP_SLTSTA_CC) {
ctrl->cmd_busy = 0;
smp_mb();
wake_up(&ctrl->queue);
}
- if (!(intr_loc & ~CMD_COMPLETED))
+ if (!(intr_loc & ~PCI_EXP_SLTSTA_CC))
return IRQ_HANDLED;
p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
/* Check MRL Sensor Changed */
- if (intr_loc & MRL_SENS_CHANGED)
+ if (intr_loc & PCI_EXP_SLTSTA_MRLSC)
pciehp_handle_switch_change(p_slot);
/* Check Attention Button Pressed */
- if (intr_loc & ATTN_BUTTN_PRESSED)
+ if (intr_loc & PCI_EXP_SLTSTA_ABP)
pciehp_handle_attention_button(p_slot);
/* Check Presence Detect Changed */
- if (intr_loc & PRSN_DETECT_CHANGED)
+ if (intr_loc & PCI_EXP_SLTSTA_PDC)
pciehp_handle_presence_change(p_slot);
/* Check Power Fault Detected */
- if (intr_loc & PWR_FAULT_DETECTED)
+ if (intr_loc & PCI_EXP_SLTSTA_PFD)
pciehp_handle_power_fault(p_slot);
return IRQ_HANDLED;
@@ -855,7 +722,7 @@ static int hpc_get_max_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
u32 lnk_cap;
int retval = 0;
- retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
+ retval = pciehp_readl(ctrl, PCI_EXP_LNKCAP, &lnk_cap);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__);
return retval;
@@ -884,13 +751,13 @@ static int hpc_get_max_lnk_width(struct slot *slot,
u32 lnk_cap;
int retval = 0;
- retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
+ retval = pciehp_readl(ctrl, PCI_EXP_LNKCAP, &lnk_cap);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__);
return retval;
}
- switch ((lnk_cap & 0x03F0) >> 4){
+ switch ((lnk_cap & PCI_EXP_LNKSTA_NLW) >> 4){
case 0:
lnk_wdth = PCIE_LNK_WIDTH_RESRV;
break;
@@ -933,14 +800,14 @@ static int hpc_get_cur_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
int retval = 0;
u16 lnk_status;
- retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
+ retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n",
__func__);
return retval;
}
- switch (lnk_status & 0x0F) {
+ switch (lnk_status & PCI_EXP_LNKSTA_CLS) {
case 1:
lnk_speed = PCIE_2PT5GB;
break;
@@ -963,14 +830,14 @@ static int hpc_get_cur_lnk_width(struct slot *slot,
int retval = 0;
u16 lnk_status;
- retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
+ retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status);
if (retval) {
ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n",
__func__);
return retval;
}
- switch ((lnk_status & 0x03F0) >> 4){
+ switch ((lnk_status & PCI_EXP_LNKSTA_NLW) >> 4){
case 0:
lnk_wdth = PCIE_LNK_WIDTH_RESRV;
break;
@@ -1036,18 +903,19 @@ int pcie_enable_notification(struct controller *ctrl)
{
u16 cmd, mask;
- cmd = PRSN_DETECT_ENABLE;
+ cmd = PCI_EXP_SLTCTL_PDCE;
if (ATTN_BUTTN(ctrl))
- cmd |= ATTN_BUTTN_ENABLE;
+ cmd |= PCI_EXP_SLTCTL_ABPE;
if (POWER_CTRL(ctrl))
- cmd |= PWR_FAULT_DETECT_ENABLE;
+ cmd |= PCI_EXP_SLTCTL_PFDE;
if (MRL_SENS(ctrl))
- cmd |= MRL_DETECT_ENABLE;
+ cmd |= PCI_EXP_SLTCTL_MRLSCE;
if (!pciehp_poll_mode)
- cmd |= HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE;
+ cmd |= PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE;
- mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE | MRL_DETECT_ENABLE |
- PWR_FAULT_DETECT_ENABLE | HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE;
+ mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
+ PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE |
+ PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE);
if (pcie_write_cmd(ctrl, cmd, mask)) {
ctrl_err(ctrl, "Cannot enable software notification\n");
@@ -1059,8 +927,9 @@ int pcie_enable_notification(struct controller *ctrl)
static void pcie_disable_notification(struct controller *ctrl)
{
u16 mask;
- mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE | MRL_DETECT_ENABLE |
- PWR_FAULT_DETECT_ENABLE | HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE;
+ mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
+ PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE |
+ PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE);
if (pcie_write_cmd(ctrl, 0, mask))
ctrl_warn(ctrl, "Cannot disable software notification\n");
}
@@ -1157,9 +1026,9 @@ static inline void dbg_ctrl(struct controller *ctrl)
EMI(ctrl) ? "yes" : "no");
ctrl_info(ctrl, " Command Completed : %3s\n",
NO_CMD_CMPL(ctrl) ? "no" : "yes");
- pciehp_readw(ctrl, SLOTSTATUS, &reg16);
+ pciehp_readw(ctrl, PCI_EXP_SLTSTA, &reg16);
ctrl_info(ctrl, "Slot Status : 0x%04x\n", reg16);
- pciehp_readw(ctrl, SLOTCTRL, &reg16);
+ pciehp_readw(ctrl, PCI_EXP_SLTCTL, &reg16);
ctrl_info(ctrl, "Slot Control : 0x%04x\n", reg16);
}
@@ -1183,7 +1052,7 @@ struct controller *pcie_init(struct pcie_device *dev)
ctrl_err(ctrl, "Cannot find PCI Express capability\n");
goto abort_ctrl;
}
- if (pciehp_readl(ctrl, SLOTCAP, &slot_cap)) {
+ if (pciehp_readl(ctrl, PCI_EXP_SLTCAP, &slot_cap)) {
ctrl_err(ctrl, "Cannot read SLOTCAP register\n");
goto abort_ctrl;
}
@@ -1208,17 +1077,17 @@ struct controller *pcie_init(struct pcie_device *dev)
ctrl->no_cmd_complete = 1;
/* Check if Data Link Layer Link Active Reporting is implemented */
- if (pciehp_readl(ctrl, LNKCAP, &link_cap)) {
+ if (pciehp_readl(ctrl, PCI_EXP_LNKCAP, &link_cap)) {
ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__);
goto abort_ctrl;
}
- if (link_cap & LINK_ACTIVE_REPORTING) {
+ if (link_cap & PCI_EXP_LNKCAP_DLLLARC) {
ctrl_dbg(ctrl, "Link Active Reporting supported\n");
ctrl->link_active_reporting = 1;
}
/* Clear all remaining event bits in Slot Status register */
- if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f))
+ if (pciehp_writew(ctrl, PCI_EXP_SLTSTA, 0x1f))
goto abort_ctrl;
/* Disable sotfware notification */
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 235fb7a5a8a5..3dfecb20d5e7 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -438,7 +438,8 @@ static struct intel_iommu *device_to_iommu(u8 bus, u8 devfn)
continue;
for (i = 0; i < drhd->devices_cnt; i++)
- if (drhd->devices[i]->bus->number == bus &&
+ if (drhd->devices[i] &&
+ drhd->devices[i]->bus->number == bus &&
drhd->devices[i]->devfn == devfn)
return drhd->iommu;
diff --git a/drivers/pci/irq.c b/drivers/pci/irq.c
index 6441dfa969a3..de01174aff06 100644
--- a/drivers/pci/irq.c
+++ b/drivers/pci/irq.c
@@ -15,7 +15,7 @@ static void pci_note_irq_problem(struct pci_dev *pdev, const char *reason)
dev_printk(KERN_ERR, &pdev->dev,
"Potentially misrouted IRQ (Bridge %s %04x:%04x)\n",
- parent->dev.bus_id, parent->vendor, parent->device);
+ dev_name(&parent->dev), parent->vendor, parent->device);
dev_printk(KERN_ERR, &pdev->dev, "%s\n", reason);
dev_printk(KERN_ERR, &pdev->dev, "Please report to linux-kernel@vger.kernel.org\n");
WARN_ON(1);
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 11a51f8ed3b3..b4a90badd0a6 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -776,28 +776,19 @@ void pci_no_msi(void)
pci_msi_enable = 0;
}
-void pci_msi_init_pci_dev(struct pci_dev *dev)
-{
- INIT_LIST_HEAD(&dev->msi_list);
-}
-
-#ifdef CONFIG_ACPI
-#include <linux/acpi.h>
-#include <linux/pci-acpi.h>
-static void __devinit msi_acpi_init(void)
+/**
+ * pci_msi_enabled - is MSI enabled?
+ *
+ * Returns true if MSI has not been disabled by the command-line option
+ * pci=nomsi.
+ **/
+int pci_msi_enabled(void)
{
- if (acpi_pci_disabled)
- return;
- pci_osc_support_set(OSC_MSI_SUPPORT);
- pcie_osc_support_set(OSC_MSI_SUPPORT);
+ return pci_msi_enable;
}
-#else
-static inline void msi_acpi_init(void) { }
-#endif /* CONFIG_ACPI */
+EXPORT_SYMBOL(pci_msi_enabled);
-void __devinit msi_init(void)
+void pci_msi_init_pci_dev(struct pci_dev *dev)
{
- if (!pci_msi_enable)
- return;
- msi_acpi_init();
+ INIT_LIST_HEAD(&dev->msi_list);
}
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index ae5ec76dca77..deea8a187eb8 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -13,8 +13,6 @@
#include <linux/module.h>
#include <linux/pci-aspm.h>
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
-#include <acpi/acresrc.h>
#include <acpi/acpi_bus.h>
#include <linux/pci-acpi.h>
@@ -24,13 +22,14 @@ struct acpi_osc_data {
acpi_handle handle;
u32 support_set;
u32 control_set;
+ u32 control_query;
+ int is_queried;
struct list_head sibiling;
};
static LIST_HEAD(acpi_osc_data_list);
struct acpi_osc_args {
u32 capbuf[3];
- u32 ctrl_result;
};
static DEFINE_MUTEX(pci_acpi_lock);
@@ -56,7 +55,7 @@ static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40,
0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
static acpi_status acpi_run_osc(acpi_handle handle,
- struct acpi_osc_args *osc_args)
+ struct acpi_osc_args *osc_args, u32 *retval)
{
acpi_status status;
struct acpi_object_list input;
@@ -112,8 +111,7 @@ static acpi_status acpi_run_osc(acpi_handle handle,
goto out_kfree;
}
out_success:
- osc_args->ctrl_result =
- *((u32 *)(out_obj->buffer.pointer + 8));
+ *retval = *((u32 *)(out_obj->buffer.pointer + 8));
status = AE_OK;
out_kfree:
@@ -121,11 +119,10 @@ out_kfree:
return status;
}
-static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data,
- u32 *result)
+static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data)
{
acpi_status status;
- u32 support_set;
+ u32 support_set, result;
struct acpi_osc_args osc_args;
/* do _OSC query for all possible controls */
@@ -134,56 +131,45 @@ static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data,
osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set;
osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
- status = acpi_run_osc(osc_data->handle, &osc_args);
+ status = acpi_run_osc(osc_data->handle, &osc_args, &result);
if (ACPI_SUCCESS(status)) {
osc_data->support_set = support_set;
- *result = osc_args.ctrl_result;
+ osc_data->control_query = result;
+ osc_data->is_queried = 1;
}
return status;
}
-static acpi_status acpi_query_osc(acpi_handle handle,
- u32 level, void *context, void **retval)
+/*
+ * pci_acpi_osc_support: Invoke _OSC indicating support for the given feature
+ * @flags: Bitmask of flags to support
+ *
+ * See the ACPI spec for the definition of the flags
+ */
+int pci_acpi_osc_support(acpi_handle handle, u32 flags)
{
acpi_status status;
- struct acpi_osc_data *osc_data;
- u32 flags = (unsigned long)context, dummy;
acpi_handle tmp;
+ struct acpi_osc_data *osc_data;
+ int rc = 0;
status = acpi_get_handle(handle, "_OSC", &tmp);
if (ACPI_FAILURE(status))
- return AE_OK;
+ return -ENOTTY;
mutex_lock(&pci_acpi_lock);
osc_data = acpi_get_osc_data(handle);
if (!osc_data) {
printk(KERN_ERR "acpi osc data array is full\n");
+ rc = -ENOMEM;
goto out;
}
- __acpi_query_osc(flags, osc_data, &dummy);
+ __acpi_query_osc(flags, osc_data);
out:
mutex_unlock(&pci_acpi_lock);
- return AE_OK;
-}
-
-/**
- * __pci_osc_support_set - register OS support to Firmware
- * @flags: OS support bits
- * @hid: hardware ID
- *
- * Update OS support fields and doing a _OSC Query to obtain an update
- * from Firmware on supported control bits.
- **/
-acpi_status __pci_osc_support_set(u32 flags, const char *hid)
-{
- if (!(flags & OSC_SUPPORT_MASKS))
- return AE_TYPE;
-
- acpi_get_devices(hid, acpi_query_osc,
- (void *)(unsigned long)flags, NULL);
- return AE_OK;
+ return rc;
}
/**
@@ -196,7 +182,7 @@ acpi_status __pci_osc_support_set(u32 flags, const char *hid)
acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
{
acpi_status status;
- u32 ctrlset, control_set, result;
+ u32 control_req, control_set, result;
acpi_handle tmp;
struct acpi_osc_data *osc_data;
struct acpi_osc_args osc_args;
@@ -213,28 +199,34 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags)
goto out;
}
- ctrlset = (flags & OSC_CONTROL_MASKS);
- if (!ctrlset) {
+ control_req = (flags & OSC_CONTROL_MASKS);
+ if (!control_req) {
status = AE_TYPE;
goto out;
}
- status = __acpi_query_osc(osc_data->support_set, osc_data, &result);
- if (ACPI_FAILURE(status))
+ /* No need to evaluate _OSC if the control was already granted. */
+ if ((osc_data->control_set & control_req) == control_req)
goto out;
- if ((result & ctrlset) != ctrlset) {
+ if (!osc_data->is_queried) {
+ status = __acpi_query_osc(osc_data->support_set, osc_data);
+ if (ACPI_FAILURE(status))
+ goto out;
+ }
+
+ if ((osc_data->control_query & control_req) != control_req) {
status = AE_SUPPORT;
goto out;
}
- control_set = osc_data->control_set | ctrlset;
+ control_set = osc_data->control_set | control_req;
osc_args.capbuf[OSC_QUERY_TYPE] = 0;
osc_args.capbuf[OSC_SUPPORT_TYPE] = osc_data->support_set;
osc_args.capbuf[OSC_CONTROL_TYPE] = control_set;
- status = acpi_run_osc(handle, &osc_args);
+ status = acpi_run_osc(handle, &osc_args, &result);
if (ACPI_SUCCESS(status))
- osc_data->control_set = control_set;
+ osc_data->control_set = result;
out:
mutex_unlock(&pci_acpi_lock);
return status;
@@ -375,7 +367,7 @@ static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle)
* The string should be the same as root bridge's name
* Please look at 'pci_scan_bus_parented'
*/
- num = sscanf(dev->bus_id, "pci%04x:%02x", &seg, &bus);
+ num = sscanf(dev_name(dev), "pci%04x:%02x", &seg, &bus);
if (num != 2)
return -ENODEV;
*handle = acpi_get_pci_rootbridge_handle(seg, bus);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 99d867bcf22a..c697f2680856 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -16,6 +16,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/sched.h>
+#include <linux/cpu.h>
#include "pci.h"
/*
@@ -48,7 +49,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
subdevice=PCI_ANY_ID, class=0, class_mask=0;
unsigned long driver_data=0;
int fields=0;
- int retval;
+ int retval=0;
fields = sscanf(buf, "%x %x %x %x %x %x %lx",
&vendor, &device, &subvendor, &subdevice,
@@ -58,16 +59,18 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
/* Only accept driver_data values that match an existing id_table
entry */
- retval = -EINVAL;
- while (ids->vendor || ids->subvendor || ids->class_mask) {
- if (driver_data == ids->driver_data) {
- retval = 0;
- break;
+ if (ids) {
+ retval = -EINVAL;
+ while (ids->vendor || ids->subvendor || ids->class_mask) {
+ if (driver_data == ids->driver_data) {
+ retval = 0;
+ break;
+ }
+ ids++;
}
- ids++;
+ if (retval) /* No match */
+ return retval;
}
- if (retval) /* No match */
- return retval;
dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
if (!dynid)
@@ -183,32 +186,43 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
return pci_match_id(drv->id_table, dev);
}
+struct drv_dev_and_id {
+ struct pci_driver *drv;
+ struct pci_dev *dev;
+ const struct pci_device_id *id;
+};
+
+static long local_pci_probe(void *_ddi)
+{
+ struct drv_dev_and_id *ddi = _ddi;
+
+ return ddi->drv->probe(ddi->dev, ddi->id);
+}
+
static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
const struct pci_device_id *id)
{
- int error;
-#ifdef CONFIG_NUMA
- /* Execute driver initialization on node where the
- device's bus is attached to. This way the driver likely
- allocates its local memory on the right node without
- any need to change it. */
- struct mempolicy *oldpol;
- cpumask_t oldmask = current->cpus_allowed;
- int node = dev_to_node(&dev->dev);
+ int error, node;
+ struct drv_dev_and_id ddi = { drv, dev, id };
+ /* Execute driver initialization on node where the device's
+ bus is attached to. This way the driver likely allocates
+ its local memory on the right node without any need to
+ change it. */
+ node = dev_to_node(&dev->dev);
if (node >= 0) {
+ int cpu;
node_to_cpumask_ptr(nodecpumask, node);
- set_cpus_allowed_ptr(current, nodecpumask);
- }
- /* And set default memory allocation policy */
- oldpol = current->mempolicy;
- current->mempolicy = NULL; /* fall back to system default policy */
-#endif
- error = drv->probe(dev, id);
-#ifdef CONFIG_NUMA
- set_cpus_allowed_ptr(current, &oldmask);
- current->mempolicy = oldpol;
-#endif
+
+ get_online_cpus();
+ cpu = cpumask_any_and(nodecpumask, cpu_online_mask);
+ if (cpu < nr_cpu_ids)
+ error = work_on_cpu(cpu, local_pci_probe, &ddi);
+ else
+ error = local_pci_probe(&ddi);
+ put_online_cpus();
+ } else
+ error = local_pci_probe(&ddi);
return error;
}
@@ -300,21 +314,12 @@ static void pci_device_shutdown(struct device *dev)
#ifdef CONFIG_PM_SLEEP
-static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
-{
- struct pci_driver *drv = pci_dev->driver;
-
- return drv && (drv->suspend || drv->suspend_late || drv->resume
- || drv->resume_early);
-}
-
/*
* Default "suspend" method for devices that have no driver provided suspend,
- * or not even a driver at all.
+ * or not even a driver at all (second part).
*/
-static void pci_default_pm_suspend(struct pci_dev *pci_dev)
+static void pci_pm_set_unknown_state(struct pci_dev *pci_dev)
{
- pci_save_state(pci_dev);
/*
* mark its power state as "unknown", since we don't know if
* e.g. the BIOS will change its device state when we suspend.
@@ -325,19 +330,9 @@ static void pci_default_pm_suspend(struct pci_dev *pci_dev)
/*
* Default "resume" method for devices that have no driver provided resume,
- * or not even a driver at all (first part).
- */
-static void pci_default_pm_resume_early(struct pci_dev *pci_dev)
-{
- /* restore the PCI config space */
- pci_restore_state(pci_dev);
-}
-
-/*
- * Default "resume" method for devices that have no driver provided resume,
* or not even a driver at all (second part).
*/
-static int pci_default_pm_resume_late(struct pci_dev *pci_dev)
+static int pci_pm_reenable_device(struct pci_dev *pci_dev)
{
int retval;
@@ -363,8 +358,16 @@ static int pci_legacy_suspend(struct device *dev, pm_message_t state)
i = drv->suspend(pci_dev, state);
suspend_report_result(drv->suspend, i);
} else {
- pci_default_pm_suspend(pci_dev);
+ pci_save_state(pci_dev);
+ /*
+ * This is for compatibility with existing code with legacy PM
+ * support.
+ */
+ pci_pm_set_unknown_state(pci_dev);
}
+
+ pci_fixup_device(pci_fixup_suspend, pci_dev);
+
return i;
}
@@ -381,32 +384,130 @@ static int pci_legacy_suspend_late(struct device *dev, pm_message_t state)
return i;
}
+static int pci_legacy_resume_early(struct device *dev)
+{
+ int error = 0;
+ struct pci_dev * pci_dev = to_pci_dev(dev);
+ struct pci_driver * drv = pci_dev->driver;
+
+ pci_fixup_device(pci_fixup_resume_early, pci_dev);
+
+ if (drv && drv->resume_early)
+ error = drv->resume_early(pci_dev);
+ return error;
+}
+
static int pci_legacy_resume(struct device *dev)
{
int error;
struct pci_dev * pci_dev = to_pci_dev(dev);
struct pci_driver * drv = pci_dev->driver;
+ pci_fixup_device(pci_fixup_resume, pci_dev);
+
if (drv && drv->resume) {
error = drv->resume(pci_dev);
} else {
- pci_default_pm_resume_early(pci_dev);
- error = pci_default_pm_resume_late(pci_dev);
+ /* restore the PCI config space */
+ pci_restore_state(pci_dev);
+ error = pci_pm_reenable_device(pci_dev);
}
return error;
}
-static int pci_legacy_resume_early(struct device *dev)
+/* Auxiliary functions used by the new power management framework */
+
+static int pci_restore_standard_config(struct pci_dev *pci_dev)
{
+ struct pci_dev *parent = pci_dev->bus->self;
int error = 0;
- struct pci_dev * pci_dev = to_pci_dev(dev);
- struct pci_driver * drv = pci_dev->driver;
- if (drv && drv->resume_early)
- error = drv->resume_early(pci_dev);
+ /* Check if the device's bus is operational */
+ if (!parent || parent->current_state == PCI_D0) {
+ pci_restore_state(pci_dev);
+ pci_update_current_state(pci_dev, PCI_D0);
+ } else {
+ dev_warn(&pci_dev->dev, "unable to restore config, "
+ "bridge %s in low power state D%d\n", pci_name(parent),
+ parent->current_state);
+ pci_dev->current_state = PCI_UNKNOWN;
+ error = -EAGAIN;
+ }
+
return error;
}
+static bool pci_is_bridge(struct pci_dev *pci_dev)
+{
+ return !!(pci_dev->subordinate);
+}
+
+static void pci_pm_default_resume_noirq(struct pci_dev *pci_dev)
+{
+ if (pci_restore_standard_config(pci_dev))
+ pci_fixup_device(pci_fixup_resume_early, pci_dev);
+}
+
+static int pci_pm_default_resume(struct pci_dev *pci_dev)
+{
+ /*
+ * pci_restore_standard_config() should have been called once already,
+ * but it would have failed if the device's parent bridge had not been
+ * in power state D0 at that time. Check it and try again if necessary.
+ */
+ if (pci_dev->current_state == PCI_UNKNOWN) {
+ int error = pci_restore_standard_config(pci_dev);
+ if (error)
+ return error;
+ }
+
+ pci_fixup_device(pci_fixup_resume, pci_dev);
+
+ if (!pci_is_bridge(pci_dev))
+ pci_enable_wake(pci_dev, PCI_D0, false);
+
+ return pci_pm_reenable_device(pci_dev);
+}
+
+static void pci_pm_default_suspend_generic(struct pci_dev *pci_dev)
+{
+ /* If device is enabled at this point, disable it */
+ pci_disable_enabled_device(pci_dev);
+ /*
+ * Save state with interrupts enabled, because in principle the bus the
+ * device is on may be put into a low power state after this code runs.
+ */
+ pci_save_state(pci_dev);
+}
+
+static void pci_pm_default_suspend(struct pci_dev *pci_dev)
+{
+ pci_pm_default_suspend_generic(pci_dev);
+
+ if (!pci_is_bridge(pci_dev))
+ pci_prepare_to_sleep(pci_dev);
+
+ pci_fixup_device(pci_fixup_suspend, pci_dev);
+}
+
+static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
+{
+ struct pci_driver *drv = pci_dev->driver;
+ bool ret = drv && (drv->suspend || drv->suspend_late || drv->resume
+ || drv->resume_early);
+
+ /*
+ * Legacy PM support is used by default, so warn if the new framework is
+ * supported as well. Drivers are supposed to support either the
+ * former, or the latter, but not both at the same time.
+ */
+ WARN_ON(ret && drv->driver.pm);
+
+ return ret;
+}
+
+/* New power management framework */
+
static int pci_pm_prepare(struct device *dev)
{
struct device_driver *drv = dev->driver;
@@ -434,15 +535,16 @@ static int pci_pm_suspend(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
- if (drv && drv->pm) {
- if (drv->pm->suspend) {
- error = drv->pm->suspend(dev);
- suspend_report_result(drv->pm->suspend, error);
- }
- } else if (pci_has_legacy_pm_support(pci_dev)) {
- error = pci_legacy_suspend(dev, PMSG_SUSPEND);
+ if (pci_has_legacy_pm_support(pci_dev))
+ return pci_legacy_suspend(dev, PMSG_SUSPEND);
+
+ if (drv && drv->pm && drv->pm->suspend) {
+ error = drv->pm->suspend(dev);
+ suspend_report_result(drv->pm->suspend, error);
}
- pci_fixup_device(pci_fixup_suspend, pci_dev);
+
+ if (!error)
+ pci_pm_default_suspend(pci_dev);
return error;
}
@@ -453,56 +555,50 @@ static int pci_pm_suspend_noirq(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
- if (drv && drv->pm) {
- if (drv->pm->suspend_noirq) {
- error = drv->pm->suspend_noirq(dev);
- suspend_report_result(drv->pm->suspend_noirq, error);
- }
- } else if (pci_has_legacy_pm_support(pci_dev)) {
- error = pci_legacy_suspend_late(dev, PMSG_SUSPEND);
- } else {
- pci_default_pm_suspend(pci_dev);
+ if (pci_has_legacy_pm_support(pci_dev))
+ return pci_legacy_suspend_late(dev, PMSG_SUSPEND);
+
+ if (drv && drv->pm && drv->pm->suspend_noirq) {
+ error = drv->pm->suspend_noirq(dev);
+ suspend_report_result(drv->pm->suspend_noirq, error);
}
+ if (!error)
+ pci_pm_set_unknown_state(pci_dev);
+
return error;
}
-static int pci_pm_resume(struct device *dev)
+static int pci_pm_resume_noirq(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct device_driver *drv = dev->driver;
int error = 0;
- pci_fixup_device(pci_fixup_resume, pci_dev);
+ if (pci_has_legacy_pm_support(pci_dev))
+ return pci_legacy_resume_early(dev);
- if (drv && drv->pm) {
- if (drv->pm->resume)
- error = drv->pm->resume(dev);
- } else if (pci_has_legacy_pm_support(pci_dev)) {
- error = pci_legacy_resume(dev);
- } else {
- error = pci_default_pm_resume_late(pci_dev);
- }
+ pci_pm_default_resume_noirq(pci_dev);
+
+ if (drv && drv->pm && drv->pm->resume_noirq)
+ error = drv->pm->resume_noirq(dev);
return error;
}
-static int pci_pm_resume_noirq(struct device *dev)
+static int pci_pm_resume(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct device_driver *drv = dev->driver;
int error = 0;
- pci_fixup_device(pci_fixup_resume_early, to_pci_dev(dev));
+ if (pci_has_legacy_pm_support(pci_dev))
+ return pci_legacy_resume(dev);
- if (drv && drv->pm) {
- if (drv->pm->resume_noirq)
- error = drv->pm->resume_noirq(dev);
- } else if (pci_has_legacy_pm_support(pci_dev)) {
- error = pci_legacy_resume_early(dev);
- } else {
- pci_default_pm_resume_early(pci_dev);
- }
+ error = pci_pm_default_resume(pci_dev);
+
+ if (!error && drv && drv->pm && drv->pm->resume)
+ error = drv->pm->resume(dev);
return error;
}
@@ -524,16 +620,17 @@ static int pci_pm_freeze(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
- if (drv && drv->pm) {
- if (drv->pm->freeze) {
- error = drv->pm->freeze(dev);
- suspend_report_result(drv->pm->freeze, error);
- }
- } else if (pci_has_legacy_pm_support(pci_dev)) {
- error = pci_legacy_suspend(dev, PMSG_FREEZE);
- pci_fixup_device(pci_fixup_suspend, pci_dev);
+ if (pci_has_legacy_pm_support(pci_dev))
+ return pci_legacy_suspend(dev, PMSG_FREEZE);
+
+ if (drv && drv->pm && drv->pm->freeze) {
+ error = drv->pm->freeze(dev);
+ suspend_report_result(drv->pm->freeze, error);
}
+ if (!error)
+ pci_pm_default_suspend_generic(pci_dev);
+
return error;
}
@@ -543,50 +640,50 @@ static int pci_pm_freeze_noirq(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
- if (drv && drv->pm) {
- if (drv->pm->freeze_noirq) {
- error = drv->pm->freeze_noirq(dev);
- suspend_report_result(drv->pm->freeze_noirq, error);
- }
- } else if (pci_has_legacy_pm_support(pci_dev)) {
- error = pci_legacy_suspend_late(dev, PMSG_FREEZE);
- } else {
- pci_default_pm_suspend(pci_dev);
+ if (pci_has_legacy_pm_support(pci_dev))
+ return pci_legacy_suspend_late(dev, PMSG_FREEZE);
+
+ if (drv && drv->pm && drv->pm->freeze_noirq) {
+ error = drv->pm->freeze_noirq(dev);
+ suspend_report_result(drv->pm->freeze_noirq, error);
}
+ if (!error)
+ pci_pm_set_unknown_state(pci_dev);
+
return error;
}
-static int pci_pm_thaw(struct device *dev)
+static int pci_pm_thaw_noirq(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct device_driver *drv = dev->driver;
int error = 0;
- if (drv && drv->pm) {
- if (drv->pm->thaw)
- error = drv->pm->thaw(dev);
- } else if (pci_has_legacy_pm_support(pci_dev)) {
- pci_fixup_device(pci_fixup_resume, pci_dev);
- error = pci_legacy_resume(dev);
- }
+ if (pci_has_legacy_pm_support(pci_dev))
+ return pci_legacy_resume_early(dev);
+
+ pci_update_current_state(pci_dev, PCI_D0);
+
+ if (drv && drv->pm && drv->pm->thaw_noirq)
+ error = drv->pm->thaw_noirq(dev);
return error;
}
-static int pci_pm_thaw_noirq(struct device *dev)
+static int pci_pm_thaw(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct device_driver *drv = dev->driver;
int error = 0;
- if (drv && drv->pm) {
- if (drv->pm->thaw_noirq)
- error = drv->pm->thaw_noirq(dev);
- } else if (pci_has_legacy_pm_support(pci_dev)) {
- pci_fixup_device(pci_fixup_resume_early, to_pci_dev(dev));
- error = pci_legacy_resume_early(dev);
- }
+ if (pci_has_legacy_pm_support(pci_dev))
+ return pci_legacy_resume(dev);
+
+ pci_pm_reenable_device(pci_dev);
+
+ if (drv && drv->pm && drv->pm->thaw)
+ error = drv->pm->thaw(dev);
return error;
}
@@ -597,17 +694,17 @@ static int pci_pm_poweroff(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
- pci_fixup_device(pci_fixup_suspend, pci_dev);
+ if (pci_has_legacy_pm_support(pci_dev))
+ return pci_legacy_suspend(dev, PMSG_HIBERNATE);
- if (drv && drv->pm) {
- if (drv->pm->poweroff) {
- error = drv->pm->poweroff(dev);
- suspend_report_result(drv->pm->poweroff, error);
- }
- } else if (pci_has_legacy_pm_support(pci_dev)) {
- error = pci_legacy_suspend(dev, PMSG_HIBERNATE);
+ if (drv && drv->pm && drv->pm->poweroff) {
+ error = drv->pm->poweroff(dev);
+ suspend_report_result(drv->pm->poweroff, error);
}
+ if (!error)
+ pci_pm_default_suspend(pci_dev);
+
return error;
}
@@ -616,54 +713,47 @@ static int pci_pm_poweroff_noirq(struct device *dev)
struct device_driver *drv = dev->driver;
int error = 0;
- if (drv && drv->pm) {
- if (drv->pm->poweroff_noirq) {
- error = drv->pm->poweroff_noirq(dev);
- suspend_report_result(drv->pm->poweroff_noirq, error);
- }
- } else if (pci_has_legacy_pm_support(to_pci_dev(dev))) {
- error = pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
+ if (pci_has_legacy_pm_support(to_pci_dev(dev)))
+ return pci_legacy_suspend_late(dev, PMSG_HIBERNATE);
+
+ if (drv && drv->pm && drv->pm->poweroff_noirq) {
+ error = drv->pm->poweroff_noirq(dev);
+ suspend_report_result(drv->pm->poweroff_noirq, error);
}
return error;
}
-static int pci_pm_restore(struct device *dev)
+static int pci_pm_restore_noirq(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct device_driver *drv = dev->driver;
int error = 0;
- if (drv && drv->pm) {
- if (drv->pm->restore)
- error = drv->pm->restore(dev);
- } else if (pci_has_legacy_pm_support(pci_dev)) {
- error = pci_legacy_resume(dev);
- } else {
- error = pci_default_pm_resume_late(pci_dev);
- }
- pci_fixup_device(pci_fixup_resume, pci_dev);
+ if (pci_has_legacy_pm_support(pci_dev))
+ return pci_legacy_resume_early(dev);
+
+ pci_pm_default_resume_noirq(pci_dev);
+
+ if (drv && drv->pm && drv->pm->restore_noirq)
+ error = drv->pm->restore_noirq(dev);
return error;
}
-static int pci_pm_restore_noirq(struct device *dev)
+static int pci_pm_restore(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct device_driver *drv = dev->driver;
int error = 0;
- pci_fixup_device(pci_fixup_resume, pci_dev);
+ if (pci_has_legacy_pm_support(pci_dev))
+ return pci_legacy_resume(dev);
- if (drv && drv->pm) {
- if (drv->pm->restore_noirq)
- error = drv->pm->restore_noirq(dev);
- } else if (pci_has_legacy_pm_support(pci_dev)) {
- error = pci_legacy_resume_early(dev);
- } else {
- pci_default_pm_resume_early(pci_dev);
- }
- pci_fixup_device(pci_fixup_resume_early, pci_dev);
+ error = pci_pm_default_resume(pci_dev);
+
+ if (!error && drv && drv->pm && drv->pm->restore)
+ error = drv->pm->restore(dev);
return error;
}
diff --git a/drivers/pci/pci-stub.c b/drivers/pci/pci-stub.c
new file mode 100644
index 000000000000..74fbec0bf6cb
--- /dev/null
+++ b/drivers/pci/pci-stub.c
@@ -0,0 +1,47 @@
+/* pci-stub - simple stub driver to reserve a pci device
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Author:
+ * Chris Wright
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ *
+ * Usage is simple, allocate a new id to the stub driver and bind the
+ * device to it. For example:
+ *
+ * # echo "8086 10f5" > /sys/bus/pci/drivers/pci-stub/new_id
+ * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind
+ * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/pci-stub/bind
+ * # ls -l /sys/bus/pci/devices/0000:00:19.0/driver
+ * .../0000:00:19.0/driver -> ../../../bus/pci/drivers/pci-stub
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+
+static int pci_stub_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ return 0;
+}
+
+static struct pci_driver stub_driver = {
+ .name = "pci-stub",
+ .id_table = NULL, /* only dynamic id's */
+ .probe = pci_stub_probe,
+};
+
+static int __init pci_stub_init(void)
+{
+ return pci_register_driver(&stub_driver);
+}
+
+static void __exit pci_stub_exit(void)
+{
+ pci_unregister_driver(&stub_driver);
+}
+
+module_init(pci_stub_init);
+module_exit(pci_stub_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Chris Wright <chrisw@sous-sol.org>");
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index c88485860a0a..db7ec14fa719 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -58,23 +58,24 @@ static ssize_t broken_parity_status_store(struct device *dev,
const char *buf, size_t count)
{
struct pci_dev *pdev = to_pci_dev(dev);
- ssize_t consumed = -EINVAL;
+ unsigned long val;
- if ((count > 0) && (*buf == '0' || *buf == '1')) {
- pdev->broken_parity_status = *buf == '1' ? 1 : 0;
- consumed = count;
- }
- return consumed;
+ if (strict_strtoul(buf, 0, &val) < 0)
+ return -EINVAL;
+
+ pdev->broken_parity_status = !!val;
+
+ return count;
}
static ssize_t local_cpus_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- cpumask_t mask;
+ const struct cpumask *mask;
int len;
- mask = pcibus_to_cpumask(to_pci_dev(dev)->bus);
- len = cpumask_scnprintf(buf, PAGE_SIZE-2, &mask);
+ mask = cpumask_of_pcibus(to_pci_dev(dev)->bus);
+ len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask);
buf[len++] = '\n';
buf[len] = '\0';
return len;
@@ -84,11 +85,11 @@ static ssize_t local_cpus_show(struct device *dev,
static ssize_t local_cpulist_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- cpumask_t mask;
+ const struct cpumask *mask;
int len;
- mask = pcibus_to_cpumask(to_pci_dev(dev)->bus);
- len = cpulist_scnprintf(buf, PAGE_SIZE-2, &mask);
+ mask = cpumask_of_pcibus(to_pci_dev(dev)->bus);
+ len = cpulist_scnprintf(buf, PAGE_SIZE-2, mask);
buf[len++] = '\n';
buf[len] = '\0';
return len;
@@ -101,11 +102,13 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf)
struct pci_dev * pci_dev = to_pci_dev(dev);
char * str = buf;
int i;
- int max = 7;
+ int max;
resource_size_t start, end;
if (pci_dev->subordinate)
max = DEVICE_COUNT_RESOURCE;
+ else
+ max = PCI_BRIDGE_RESOURCES;
for (i = 0; i < max; i++) {
struct resource *res = &pci_dev->resource[i];
@@ -133,19 +136,23 @@ static ssize_t is_enabled_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
- ssize_t result = -EINVAL;
struct pci_dev *pdev = to_pci_dev(dev);
+ unsigned long val;
+ ssize_t result = strict_strtoul(buf, 0, &val);
+
+ if (result < 0)
+ return result;
/* this can crash the machine when done on the "wrong" device */
if (!capable(CAP_SYS_ADMIN))
- return count;
+ return -EPERM;
- if (*buf == '0') {
+ if (!val) {
if (atomic_read(&pdev->enable_cnt) != 0)
pci_disable_device(pdev);
else
result = -EIO;
- } else if (*buf == '1')
+ } else
result = pci_enable_device(pdev);
return result < 0 ? result : count;
@@ -185,25 +192,28 @@ msi_bus_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct pci_dev *pdev = to_pci_dev(dev);
+ unsigned long val;
+
+ if (strict_strtoul(buf, 0, &val) < 0)
+ return -EINVAL;
/* bad things may happen if the no_msi flag is changed
* while some drivers are loaded */
if (!capable(CAP_SYS_ADMIN))
- return count;
+ return -EPERM;
+ /* Maybe pci devices without subordinate busses shouldn't even have this
+ * attribute in the first place? */
if (!pdev->subordinate)
return count;
- if (*buf == '0') {
- pdev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
- dev_warn(&pdev->dev, "forced subordinate bus to not support MSI,"
- " bad things could happen.\n");
- }
+ /* Is the flag going to change, or keep the value it already had? */
+ if (!(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI) ^
+ !!val) {
+ pdev->subordinate->bus_flags ^= PCI_BUS_FLAGS_NO_MSI;
- if (*buf == '1') {
- pdev->subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI;
- dev_warn(&pdev->dev, "forced subordinate bus to support MSI,"
- " bad things could happen.\n");
+ dev_warn(&pdev->dev, "forced subordinate bus to%s support MSI,"
+ " bad things could happen\n", val ? "" : " not");
}
return count;
@@ -361,55 +371,33 @@ pci_write_config(struct kobject *kobj, struct bin_attribute *bin_attr,
}
static ssize_t
-pci_read_vpd(struct kobject *kobj, struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+read_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct pci_dev *dev =
to_pci_dev(container_of(kobj, struct device, kobj));
- int end;
- int ret;
if (off > bin_attr->size)
count = 0;
else if (count > bin_attr->size - off)
count = bin_attr->size - off;
- end = off + count;
-
- while (off < end) {
- ret = dev->vpd->ops->read(dev, off, end - off, buf);
- if (ret < 0)
- return ret;
- buf += ret;
- off += ret;
- }
- return count;
+ return pci_read_vpd(dev, off, count, buf);
}
static ssize_t
-pci_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+write_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct pci_dev *dev =
to_pci_dev(container_of(kobj, struct device, kobj));
- int end;
- int ret;
if (off > bin_attr->size)
count = 0;
else if (count > bin_attr->size - off)
count = bin_attr->size - off;
- end = off + count;
-
- while (off < end) {
- ret = dev->vpd->ops->write(dev, off, end - off, buf);
- if (ret < 0)
- return ret;
- buf += ret;
- off += ret;
- }
- return count;
+ return pci_write_vpd(dev, off, count, buf);
}
#ifdef HAVE_PCI_LEGACY
@@ -569,7 +557,7 @@ void pci_remove_legacy_files(struct pci_bus *b)
#ifdef HAVE_PCI_MMAP
-static int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma)
+int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma)
{
unsigned long nr, start, size;
@@ -620,6 +608,9 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
vma->vm_pgoff += start >> PAGE_SHIFT;
mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
+ if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(start))
+ return -EINVAL;
+
return pci_mmap_page_range(pdev, vma, mmap_type, write_combine);
}
@@ -832,8 +823,8 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
attr->size = dev->vpd->len;
attr->attr.name = "vpd";
attr->attr.mode = S_IRUSR | S_IWUSR;
- attr->read = pci_read_vpd;
- attr->write = pci_write_vpd;
+ attr->read = read_vpd_attr;
+ attr->write = write_vpd_attr;
retval = sysfs_create_bin_file(&dev->dev.kobj, attr);
if (retval) {
kfree(dev->vpd->attr);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 061d1ee0046a..e491fdedf705 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -56,6 +56,22 @@ unsigned char pci_bus_max_busnr(struct pci_bus* bus)
}
EXPORT_SYMBOL_GPL(pci_bus_max_busnr);
+#ifdef CONFIG_HAS_IOMEM
+void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar)
+{
+ /*
+ * Make sure the BAR is actually a memory resource, not an IO resource
+ */
+ if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
+ WARN_ON(1);
+ return NULL;
+ }
+ return ioremap_nocache(pci_resource_start(pdev, bar),
+ pci_resource_len(pdev, bar));
+}
+EXPORT_SYMBOL_GPL(pci_ioremap_bar);
+#endif
+
#if 0
/**
* pci_max_busnr - returns maximum PCI bus number
@@ -360,25 +376,10 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
static void
pci_restore_bars(struct pci_dev *dev)
{
- int i, numres;
-
- switch (dev->hdr_type) {
- case PCI_HEADER_TYPE_NORMAL:
- numres = 6;
- break;
- case PCI_HEADER_TYPE_BRIDGE:
- numres = 2;
- break;
- case PCI_HEADER_TYPE_CARDBUS:
- numres = 1;
- break;
- default:
- /* Should never get here, but just in case... */
- return;
- }
+ int i;
- for (i = 0; i < numres; i ++)
- pci_update_resource(dev, &dev->resource[i], i);
+ for (i = 0; i < PCI_BRIDGE_RESOURCES; i++)
+ pci_update_resource(dev, i);
}
static struct pci_platform_pm_ops *pci_platform_pm;
@@ -524,14 +525,17 @@ pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
* pci_update_current_state - Read PCI power state of given device from its
* PCI PM registers and cache it
* @dev: PCI device to handle.
+ * @state: State to cache in case the device doesn't have the PM capability
*/
-static void pci_update_current_state(struct pci_dev *dev)
+void pci_update_current_state(struct pci_dev *dev, pci_power_t state)
{
if (dev->pm_cap) {
u16 pmcsr;
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
+ } else {
+ dev->current_state = state;
}
}
@@ -574,7 +578,7 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
*/
int ret = platform_pci_set_power_state(dev, PCI_D0);
if (!ret)
- pci_update_current_state(dev);
+ pci_update_current_state(dev, PCI_D0);
}
/* This device is quirked not to be put into D3, so
don't put it in D3 */
@@ -587,7 +591,7 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
/* Allow the platform to finalize the transition */
int ret = platform_pci_set_power_state(dev, state);
if (!ret) {
- pci_update_current_state(dev);
+ pci_update_current_state(dev, state);
error = 0;
}
}
@@ -640,19 +644,14 @@ static int pci_save_pcie_state(struct pci_dev *dev)
int pos, i = 0;
struct pci_cap_saved_state *save_state;
u16 *cap;
- int found = 0;
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
if (pos <= 0)
return 0;
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
- if (!save_state)
- save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
- else
- found = 1;
if (!save_state) {
- dev_err(&dev->dev, "out of memory in pci_save_pcie_state\n");
+ dev_err(&dev->dev, "buffer not found in %s\n", __FUNCTION__);
return -ENOMEM;
}
cap = (u16 *)&save_state->data[0];
@@ -661,9 +660,7 @@ static int pci_save_pcie_state(struct pci_dev *dev)
pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
- save_state->cap_nr = PCI_CAP_ID_EXP;
- if (!found)
- pci_add_saved_cap(dev, save_state);
+
return 0;
}
@@ -688,30 +685,21 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
static int pci_save_pcix_state(struct pci_dev *dev)
{
- int pos, i = 0;
+ int pos;
struct pci_cap_saved_state *save_state;
- u16 *cap;
- int found = 0;
pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
if (pos <= 0)
return 0;
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX);
- if (!save_state)
- save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL);
- else
- found = 1;
if (!save_state) {
- dev_err(&dev->dev, "out of memory in pci_save_pcie_state\n");
+ dev_err(&dev->dev, "buffer not found in %s\n", __FUNCTION__);
return -ENOMEM;
}
- cap = (u16 *)&save_state->data[0];
- pci_read_config_word(dev, pos + PCI_X_CMD, &cap[i++]);
- save_state->cap_nr = PCI_CAP_ID_PCIX;
- if (!found)
- pci_add_saved_cap(dev, save_state);
+ pci_read_config_word(dev, pos + PCI_X_CMD, (u16 *)save_state->data);
+
return 0;
}
@@ -982,6 +970,32 @@ void pcim_pin_device(struct pci_dev *pdev)
*/
void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {}
+static void do_pci_disable_device(struct pci_dev *dev)
+{
+ u16 pci_command;
+
+ pci_read_config_word(dev, PCI_COMMAND, &pci_command);
+ if (pci_command & PCI_COMMAND_MASTER) {
+ pci_command &= ~PCI_COMMAND_MASTER;
+ pci_write_config_word(dev, PCI_COMMAND, pci_command);
+ }
+
+ pcibios_disable_device(dev);
+}
+
+/**
+ * pci_disable_enabled_device - Disable device without updating enable_cnt
+ * @dev: PCI device to disable
+ *
+ * NOTE: This function is a backend of PCI power management routines and is
+ * not supposed to be called drivers.
+ */
+void pci_disable_enabled_device(struct pci_dev *dev)
+{
+ if (atomic_read(&dev->enable_cnt))
+ do_pci_disable_device(dev);
+}
+
/**
* pci_disable_device - Disable PCI device after use
* @dev: PCI device to be disabled
@@ -996,7 +1010,6 @@ void
pci_disable_device(struct pci_dev *dev)
{
struct pci_devres *dr;
- u16 pci_command;
dr = find_pci_dr(dev);
if (dr)
@@ -1005,14 +1018,9 @@ pci_disable_device(struct pci_dev *dev)
if (atomic_sub_return(1, &dev->enable_cnt) != 0)
return;
- pci_read_config_word(dev, PCI_COMMAND, &pci_command);
- if (pci_command & PCI_COMMAND_MASTER) {
- pci_command &= ~PCI_COMMAND_MASTER;
- pci_write_config_word(dev, PCI_COMMAND, pci_command);
- }
- dev->is_busmaster = 0;
+ do_pci_disable_device(dev);
- pcibios_disable_device(dev);
+ dev->is_busmaster = 0;
}
/**
@@ -1107,7 +1115,7 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable)
int error = 0;
bool pme_done = false;
- if (!device_may_wakeup(&dev->dev))
+ if (enable && !device_may_wakeup(&dev->dev))
return -EINVAL;
/*
@@ -1301,6 +1309,71 @@ void pci_pm_init(struct pci_dev *dev)
}
/**
+ * platform_pci_wakeup_init - init platform wakeup if present
+ * @dev: PCI device
+ *
+ * Some devices don't have PCI PM caps but can still generate wakeup
+ * events through platform methods (like ACPI events). If @dev supports
+ * platform wakeup events, set the device flag to indicate as much. This
+ * may be redundant if the device also supports PCI PM caps, but double
+ * initialization should be safe in that case.
+ */
+void platform_pci_wakeup_init(struct pci_dev *dev)
+{
+ if (!platform_pci_can_wakeup(dev))
+ return;
+
+ device_set_wakeup_capable(&dev->dev, true);
+ device_set_wakeup_enable(&dev->dev, false);
+ platform_pci_sleep_wake(dev, false);
+}
+
+/**
+ * pci_add_save_buffer - allocate buffer for saving given capability registers
+ * @dev: the PCI device
+ * @cap: the capability to allocate the buffer for
+ * @size: requested size of the buffer
+ */
+static int pci_add_cap_save_buffer(
+ struct pci_dev *dev, char cap, unsigned int size)
+{
+ int pos;
+ struct pci_cap_saved_state *save_state;
+
+ pos = pci_find_capability(dev, cap);
+ if (pos <= 0)
+ return 0;
+
+ save_state = kzalloc(sizeof(*save_state) + size, GFP_KERNEL);
+ if (!save_state)
+ return -ENOMEM;
+
+ save_state->cap_nr = cap;
+ pci_add_saved_cap(dev, save_state);
+
+ return 0;
+}
+
+/**
+ * pci_allocate_cap_save_buffers - allocate buffers for saving capabilities
+ * @dev: the PCI device
+ */
+void pci_allocate_cap_save_buffers(struct pci_dev *dev)
+{
+ int error;
+
+ error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_EXP, 4 * sizeof(u16));
+ if (error)
+ dev_err(&dev->dev,
+ "unable to preallocate PCI Express save buffer\n");
+
+ error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_PCIX, sizeof(u16));
+ if (error)
+ dev_err(&dev->dev,
+ "unable to preallocate PCI-X save buffer\n");
+}
+
+/**
* pci_enable_ari - enable ARI forwarding if hardware support it
* @dev: the PCI device
*/
@@ -1337,6 +1410,20 @@ void pci_enable_ari(struct pci_dev *dev)
bridge->ari_enabled = 1;
}
+/**
+ * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
+ * @dev: the PCI device
+ * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)
+ *
+ * Perform INTx swizzling for a device behind one level of bridge. This is
+ * required by section 9.1 of the PCI-to-PCI bridge specification for devices
+ * behind bridges on add-in cards.
+ */
+u8 pci_swizzle_interrupt_pin(struct pci_dev *dev, u8 pin)
+{
+ return (((pin - 1) + PCI_SLOT(dev->devfn)) % 4) + 1;
+}
+
int
pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
{
@@ -1345,9 +1432,9 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
pin = dev->pin;
if (!pin)
return -1;
- pin--;
+
while (dev->bus->self) {
- pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+ pin = pci_swizzle_interrupt_pin(dev, pin);
dev = dev->bus->self;
}
*bridge = dev;
@@ -1355,6 +1442,26 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
}
/**
+ * pci_common_swizzle - swizzle INTx all the way to root bridge
+ * @dev: the PCI device
+ * @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD)
+ *
+ * Perform INTx swizzling for a device. This traverses through all PCI-to-PCI
+ * bridges all the way up to a PCI root bus.
+ */
+u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+ u8 pin = *pinp;
+
+ while (dev->bus->self) {
+ pin = pci_swizzle_interrupt_pin(dev, pin);
+ dev = dev->bus->self;
+ }
+ *pinp = pin;
+ return PCI_SLOT(dev->devfn);
+}
+
+/**
* pci_release_region - Release a PCI bar
* @pdev: PCI device whose resources were previously reserved by pci_request_region
* @bar: BAR to release
@@ -1395,7 +1502,8 @@ void pci_release_region(struct pci_dev *pdev, int bar)
* Returns 0 on success, or %EBUSY on error. A warning
* message is also printed on failure.
*/
-int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
+static int __pci_request_region(struct pci_dev *pdev, int bar, const char *res_name,
+ int exclusive)
{
struct pci_devres *dr;
@@ -1408,8 +1516,9 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
goto err_out;
}
else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
- if (!request_mem_region(pci_resource_start(pdev, bar),
- pci_resource_len(pdev, bar), res_name))
+ if (!__request_mem_region(pci_resource_start(pdev, bar),
+ pci_resource_len(pdev, bar), res_name,
+ exclusive))
goto err_out;
}
@@ -1428,6 +1537,47 @@ err_out:
}
/**
+ * pci_request_region - Reserved PCI I/O and memory resource
+ * @pdev: PCI device whose resources are to be reserved
+ * @bar: BAR to be reserved
+ * @res_name: Name to be associated with resource.
+ *
+ * Mark the PCI region associated with PCI device @pdev BR @bar as
+ * being reserved by owner @res_name. Do not access any
+ * address inside the PCI regions unless this call returns
+ * successfully.
+ *
+ * Returns 0 on success, or %EBUSY on error. A warning
+ * message is also printed on failure.
+ */
+int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
+{
+ return __pci_request_region(pdev, bar, res_name, 0);
+}
+
+/**
+ * pci_request_region_exclusive - Reserved PCI I/O and memory resource
+ * @pdev: PCI device whose resources are to be reserved
+ * @bar: BAR to be reserved
+ * @res_name: Name to be associated with resource.
+ *
+ * Mark the PCI region associated with PCI device @pdev BR @bar as
+ * being reserved by owner @res_name. Do not access any
+ * address inside the PCI regions unless this call returns
+ * successfully.
+ *
+ * Returns 0 on success, or %EBUSY on error. A warning
+ * message is also printed on failure.
+ *
+ * The key difference that _exclusive makes it that userspace is
+ * explicitly not allowed to map the resource via /dev/mem or
+ * sysfs.
+ */
+int pci_request_region_exclusive(struct pci_dev *pdev, int bar, const char *res_name)
+{
+ return __pci_request_region(pdev, bar, res_name, IORESOURCE_EXCLUSIVE);
+}
+/**
* pci_release_selected_regions - Release selected PCI I/O and memory resources
* @pdev: PCI device whose resources were previously reserved
* @bars: Bitmask of BARs to be released
@@ -1444,20 +1594,14 @@ void pci_release_selected_regions(struct pci_dev *pdev, int bars)
pci_release_region(pdev, i);
}
-/**
- * pci_request_selected_regions - Reserve selected PCI I/O and memory resources
- * @pdev: PCI device whose resources are to be reserved
- * @bars: Bitmask of BARs to be requested
- * @res_name: Name to be associated with resource
- */
-int pci_request_selected_regions(struct pci_dev *pdev, int bars,
- const char *res_name)
+int __pci_request_selected_regions(struct pci_dev *pdev, int bars,
+ const char *res_name, int excl)
{
int i;
for (i = 0; i < 6; i++)
if (bars & (1 << i))
- if(pci_request_region(pdev, i, res_name))
+ if (__pci_request_region(pdev, i, res_name, excl))
goto err_out;
return 0;
@@ -1469,6 +1613,26 @@ err_out:
return -EBUSY;
}
+
+/**
+ * pci_request_selected_regions - Reserve selected PCI I/O and memory resources
+ * @pdev: PCI device whose resources are to be reserved
+ * @bars: Bitmask of BARs to be requested
+ * @res_name: Name to be associated with resource
+ */
+int pci_request_selected_regions(struct pci_dev *pdev, int bars,
+ const char *res_name)
+{
+ return __pci_request_selected_regions(pdev, bars, res_name, 0);
+}
+
+int pci_request_selected_regions_exclusive(struct pci_dev *pdev,
+ int bars, const char *res_name)
+{
+ return __pci_request_selected_regions(pdev, bars, res_name,
+ IORESOURCE_EXCLUSIVE);
+}
+
/**
* pci_release_regions - Release reserved PCI I/O and memory resources
* @pdev: PCI device whose resources were previously reserved by pci_request_regions
@@ -1502,27 +1666,66 @@ int pci_request_regions(struct pci_dev *pdev, const char *res_name)
}
/**
+ * pci_request_regions_exclusive - Reserved PCI I/O and memory resources
+ * @pdev: PCI device whose resources are to be reserved
+ * @res_name: Name to be associated with resource.
+ *
+ * Mark all PCI regions associated with PCI device @pdev as
+ * being reserved by owner @res_name. Do not access any
+ * address inside the PCI regions unless this call returns
+ * successfully.
+ *
+ * pci_request_regions_exclusive() will mark the region so that
+ * /dev/mem and the sysfs MMIO access will not be allowed.
+ *
+ * Returns 0 on success, or %EBUSY on error. A warning
+ * message is also printed on failure.
+ */
+int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name)
+{
+ return pci_request_selected_regions_exclusive(pdev,
+ ((1 << 6) - 1), res_name);
+}
+
+static void __pci_set_master(struct pci_dev *dev, bool enable)
+{
+ u16 old_cmd, cmd;
+
+ pci_read_config_word(dev, PCI_COMMAND, &old_cmd);
+ if (enable)
+ cmd = old_cmd | PCI_COMMAND_MASTER;
+ else
+ cmd = old_cmd & ~PCI_COMMAND_MASTER;
+ if (cmd != old_cmd) {
+ dev_dbg(&dev->dev, "%s bus mastering\n",
+ enable ? "enabling" : "disabling");
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ dev->is_busmaster = enable;
+}
+
+/**
* pci_set_master - enables bus-mastering for device dev
* @dev: the PCI device to enable
*
* Enables bus-mastering on the device and calls pcibios_set_master()
* to do the needed arch specific settings.
*/
-void
-pci_set_master(struct pci_dev *dev)
+void pci_set_master(struct pci_dev *dev)
{
- u16 cmd;
-
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
- if (! (cmd & PCI_COMMAND_MASTER)) {
- dev_dbg(&dev->dev, "enabling bus mastering\n");
- cmd |= PCI_COMMAND_MASTER;
- pci_write_config_word(dev, PCI_COMMAND, cmd);
- }
- dev->is_busmaster = 1;
+ __pci_set_master(dev, true);
pcibios_set_master(dev);
}
+/**
+ * pci_clear_master - disables bus-mastering for device dev
+ * @dev: the PCI device to disable
+ */
+void pci_clear_master(struct pci_dev *dev)
+{
+ __pci_set_master(dev, false);
+}
+
#ifdef PCI_DISABLE_MWI
int pci_set_mwi(struct pci_dev *dev)
{
@@ -1751,24 +1954,7 @@ int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask)
EXPORT_SYMBOL(pci_set_dma_seg_boundary);
#endif
-/**
- * pci_execute_reset_function() - Reset a PCI device function
- * @dev: Device function to reset
- *
- * Some devices allow an individual function to be reset without affecting
- * other functions in the same device. The PCI device must be responsive
- * to PCI config space in order to use this function.
- *
- * The device function is presumed to be unused when this function is called.
- * Resetting the device will make the contents of PCI configuration space
- * random, so any caller of this must be prepared to reinitialise the
- * device including MSI, bus mastering, BARs, decoding IO and memory spaces,
- * etc.
- *
- * Returns 0 if the device function was successfully reset or -ENOTTY if the
- * device doesn't support resetting a single function.
- */
-int pci_execute_reset_function(struct pci_dev *dev)
+static int __pcie_flr(struct pci_dev *dev, int probe)
{
u16 status;
u32 cap;
@@ -1780,6 +1966,9 @@ int pci_execute_reset_function(struct pci_dev *dev)
if (!(cap & PCI_EXP_DEVCAP_FLR))
return -ENOTTY;
+ if (probe)
+ return 0;
+
pci_block_user_cfg_access(dev);
/* Wait for Transaction Pending bit clean */
@@ -1802,6 +1991,80 @@ int pci_execute_reset_function(struct pci_dev *dev)
pci_unblock_user_cfg_access(dev);
return 0;
}
+
+static int __pci_af_flr(struct pci_dev *dev, int probe)
+{
+ int cappos = pci_find_capability(dev, PCI_CAP_ID_AF);
+ u8 status;
+ u8 cap;
+
+ if (!cappos)
+ return -ENOTTY;
+ pci_read_config_byte(dev, cappos + PCI_AF_CAP, &cap);
+ if (!(cap & PCI_AF_CAP_TP) || !(cap & PCI_AF_CAP_FLR))
+ return -ENOTTY;
+
+ if (probe)
+ return 0;
+
+ pci_block_user_cfg_access(dev);
+
+ /* Wait for Transaction Pending bit clean */
+ msleep(100);
+ pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status);
+ if (status & PCI_AF_STATUS_TP) {
+ dev_info(&dev->dev, "Busy after 100ms while trying to"
+ " reset; sleeping for 1 second\n");
+ ssleep(1);
+ pci_read_config_byte(dev,
+ cappos + PCI_AF_STATUS, &status);
+ if (status & PCI_AF_STATUS_TP)
+ dev_info(&dev->dev, "Still busy after 1s; "
+ "proceeding with reset anyway\n");
+ }
+ pci_write_config_byte(dev, cappos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
+ mdelay(100);
+
+ pci_unblock_user_cfg_access(dev);
+ return 0;
+}
+
+static int __pci_reset_function(struct pci_dev *pdev, int probe)
+{
+ int res;
+
+ res = __pcie_flr(pdev, probe);
+ if (res != -ENOTTY)
+ return res;
+
+ res = __pci_af_flr(pdev, probe);
+ if (res != -ENOTTY)
+ return res;
+
+ return res;
+}
+
+/**
+ * pci_execute_reset_function() - Reset a PCI device function
+ * @dev: Device function to reset
+ *
+ * Some devices allow an individual function to be reset without affecting
+ * other functions in the same device. The PCI device must be responsive
+ * to PCI config space in order to use this function.
+ *
+ * The device function is presumed to be unused when this function is called.
+ * Resetting the device will make the contents of PCI configuration space
+ * random, so any caller of this must be prepared to reinitialise the
+ * device including MSI, bus mastering, BARs, decoding IO and memory spaces,
+ * etc.
+ *
+ * Returns 0 if the device function was successfully reset or -ENOTTY if the
+ * device doesn't support resetting a single function.
+ */
+int pci_execute_reset_function(struct pci_dev *dev)
+{
+ return __pci_reset_function(dev, 0);
+}
EXPORT_SYMBOL_GPL(pci_execute_reset_function);
/**
@@ -1822,15 +2085,10 @@ EXPORT_SYMBOL_GPL(pci_execute_reset_function);
*/
int pci_reset_function(struct pci_dev *dev)
{
- u32 cap;
- int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP);
- int r;
+ int r = __pci_reset_function(dev, 1);
- if (!exppos)
- return -ENOTTY;
- pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap);
- if (!(cap & PCI_EXP_DEVCAP_FLR))
- return -ENOTTY;
+ if (r < 0)
+ return r;
if (!dev->msi_enabled && !dev->msix_enabled && dev->irq != 0)
disable_irq(dev->irq);
@@ -2022,6 +2280,28 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags)
return bars;
}
+/**
+ * pci_resource_bar - get position of the BAR associated with a resource
+ * @dev: the PCI device
+ * @resno: the resource number
+ * @type: the BAR type to be filled in
+ *
+ * Returns BAR position in config space, or 0 if the BAR is invalid.
+ */
+int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
+{
+ if (resno < PCI_ROM_RESOURCE) {
+ *type = pci_bar_unknown;
+ return PCI_BASE_ADDRESS_0 + 4 * resno;
+ } else if (resno == PCI_ROM_RESOURCE) {
+ *type = pci_bar_mem32;
+ return dev->rom_base_reg;
+ }
+
+ dev_err(&dev->dev, "BAR: invalid resource #%d\n", resno);
+ return 0;
+}
+
static void __devinit pci_no_domains(void)
{
#ifdef CONFIG_PCI_DOMAINS
@@ -2029,6 +2309,19 @@ static void __devinit pci_no_domains(void)
#endif
}
+/**
+ * pci_ext_cfg_enabled - can we access extended PCI config space?
+ * @dev: The PCI device of the root bridge.
+ *
+ * Returns 1 if we can access PCI extended config space (offsets
+ * greater than 0xff). This is the default implementation. Architecture
+ * implementations can override this.
+ */
+int __attribute__ ((weak)) pci_ext_cfg_avail(struct pci_dev *dev)
+{
+ return 1;
+}
+
static int __devinit pci_init(void)
{
struct pci_dev *dev = NULL;
@@ -2037,8 +2330,6 @@ static int __devinit pci_init(void)
pci_fixup_device(pci_fixup_final, dev);
}
- msi_init();
-
return 0;
}
@@ -2083,11 +2374,15 @@ EXPORT_SYMBOL(pci_find_capability);
EXPORT_SYMBOL(pci_bus_find_capability);
EXPORT_SYMBOL(pci_release_regions);
EXPORT_SYMBOL(pci_request_regions);
+EXPORT_SYMBOL(pci_request_regions_exclusive);
EXPORT_SYMBOL(pci_release_region);
EXPORT_SYMBOL(pci_request_region);
+EXPORT_SYMBOL(pci_request_region_exclusive);
EXPORT_SYMBOL(pci_release_selected_regions);
EXPORT_SYMBOL(pci_request_selected_regions);
+EXPORT_SYMBOL(pci_request_selected_regions_exclusive);
EXPORT_SYMBOL(pci_set_master);
+EXPORT_SYMBOL(pci_clear_master);
EXPORT_SYMBOL(pci_set_mwi);
EXPORT_SYMBOL(pci_try_set_mwi);
EXPORT_SYMBOL(pci_clear_mwi);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 9de87e9f98f5..1351bb4addde 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -10,6 +10,10 @@ extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_cleanup_rom(struct pci_dev *dev);
+#ifdef HAVE_PCI_MMAP
+extern int pci_mmap_fits(struct pci_dev *pdev, int resno,
+ struct vm_area_struct *vma);
+#endif
/**
* Firmware PM callbacks
@@ -40,7 +44,11 @@ struct pci_platform_pm_ops {
};
extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
+extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
+extern void pci_disable_enabled_device(struct pci_dev *dev);
extern void pci_pm_init(struct pci_dev *dev);
+extern void platform_pci_wakeup_init(struct pci_dev *dev);
+extern void pci_allocate_cap_save_buffers(struct pci_dev *dev);
extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
extern int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val);
@@ -50,14 +58,14 @@ extern int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val);
extern int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val);
struct pci_vpd_ops {
- int (*read)(struct pci_dev *dev, int pos, int size, char *buf);
- int (*write)(struct pci_dev *dev, int pos, int size, const char *buf);
+ ssize_t (*read)(struct pci_dev *dev, loff_t pos, size_t count, void *buf);
+ ssize_t (*write)(struct pci_dev *dev, loff_t pos, size_t count, const void *buf);
void (*release)(struct pci_dev *dev);
};
struct pci_vpd {
unsigned int len;
- struct pci_vpd_ops *ops;
+ const struct pci_vpd_ops *ops;
struct bin_attribute *attr; /* descriptor for sysfs VPD entry */
};
@@ -98,11 +106,9 @@ extern unsigned int pci_pm_d3_delay;
#ifdef CONFIG_PCI_MSI
void pci_no_msi(void);
extern void pci_msi_init_pci_dev(struct pci_dev *dev);
-extern void __devinit msi_init(void);
#else
static inline void pci_no_msi(void) { }
static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
-static inline void msi_init(void) { }
#endif
#ifdef CONFIG_PCIEAER
@@ -159,16 +165,28 @@ struct pci_slot_attribute {
};
#define to_pci_slot_attr(s) container_of(s, struct pci_slot_attribute, attr)
+enum pci_bar_type {
+ pci_bar_unknown, /* Standard PCI BAR probe */
+ pci_bar_io, /* An io port BAR */
+ pci_bar_mem32, /* A 32-bit memory BAR */
+ pci_bar_mem64, /* A 64-bit memory BAR */
+};
+
+extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
+ struct resource *res, unsigned int reg);
+extern int pci_resource_bar(struct pci_dev *dev, int resno,
+ enum pci_bar_type *type);
+extern int pci_bus_add_child(struct pci_bus *bus);
extern void pci_enable_ari(struct pci_dev *dev);
/**
* pci_ari_enabled - query ARI forwarding status
- * @dev: the PCI device
+ * @bus: the PCI bus
*
* Returns 1 if ARI forwarding is enabled, or 0 if not enabled;
*/
-static inline int pci_ari_enabled(struct pci_dev *dev)
+static inline int pci_ari_enabled(struct pci_bus *bus)
{
- return dev->ari_enabled;
+ return bus->self && bus->self->ari_enabled;
}
#endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c
index 6dd7b13e9808..ebce26c37049 100644
--- a/drivers/pci/pcie/aer/aerdrv_acpi.c
+++ b/drivers/pci/pcie/aer/aerdrv_acpi.c
@@ -38,7 +38,6 @@ int aer_osc_setup(struct pcie_device *pciedev)
handle = acpi_find_root_bridge_handle(pdev);
if (handle) {
- pcie_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
status = pci_osc_control_set(handle,
OSC_PCI_EXPRESS_AER_CONTROL |
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c
index 3933d4f30e8c..0fc29ae80df8 100644
--- a/drivers/pci/pcie/aer/aerdrv_errprint.c
+++ b/drivers/pci/pcie/aer/aerdrv_errprint.c
@@ -233,7 +233,7 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
if (info->flags & AER_TLP_HEADER_VALID_FLAG) {
unsigned char *tlp = (unsigned char *) &info->tlp;
- printk("%sTLB Header:\n", loglevel);
+ printk("%sTLP Header:\n", loglevel);
printk("%s%02x%02x%02x%02x %02x%02x%02x%02x"
" %02x%02x%02x%02x %02x%02x%02x%02x\n",
loglevel,
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 9aad608bcf3f..586b6f75910d 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
+#include <linux/delay.h>
#include <linux/pci-aspm.h>
#include "../pci.h"
@@ -33,6 +34,11 @@ struct endpoint_state {
struct pcie_link_state {
struct list_head sibiling;
struct pci_dev *pdev;
+ bool downstream_has_switch;
+
+ struct pcie_link_state *parent;
+ struct list_head children;
+ struct list_head link;
/* ASPM state */
unsigned int support_state;
@@ -70,6 +76,8 @@ static const char *policy_str[] = {
[POLICY_POWERSAVE] = "powersave"
};
+#define LINK_RETRAIN_TIMEOUT HZ
+
static int policy_to_aspm_state(struct pci_dev *pdev)
{
struct pcie_link_state *link_state = pdev->link_state;
@@ -125,7 +133,7 @@ static void pcie_set_clock_pm(struct pci_dev *pdev, int enable)
link_state->clk_pm_enabled = !!enable;
}
-static void pcie_check_clock_pm(struct pci_dev *pdev)
+static void pcie_check_clock_pm(struct pci_dev *pdev, int blacklist)
{
int pos;
u32 reg32;
@@ -149,10 +157,26 @@ static void pcie_check_clock_pm(struct pci_dev *pdev)
if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN))
enabled = 0;
}
- link_state->clk_pm_capable = capable;
link_state->clk_pm_enabled = enabled;
link_state->bios_clk_state = enabled;
- pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev));
+ if (!blacklist) {
+ link_state->clk_pm_capable = capable;
+ pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev));
+ } else {
+ link_state->clk_pm_capable = 0;
+ pcie_set_clock_pm(pdev, 0);
+ }
+}
+
+static bool pcie_aspm_downstream_has_switch(struct pci_dev *pdev)
+{
+ struct pci_dev *child_dev;
+
+ list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
+ if (child_dev->pcie_type == PCI_EXP_TYPE_UPSTREAM)
+ return true;
+ }
+ return false;
}
/*
@@ -217,16 +241,18 @@ static void pcie_aspm_configure_common_clock(struct pci_dev *pdev)
pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16);
/* Wait for link training end */
- /* break out after waiting for 1 second */
+ /* break out after waiting for timeout */
start_jiffies = jiffies;
- while ((jiffies - start_jiffies) < HZ) {
+ for (;;) {
pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, &reg16);
if (!(reg16 & PCI_EXP_LNKSTA_LT))
break;
- cpu_relax();
+ if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT))
+ break;
+ msleep(1);
}
/* training failed -> recover */
- if ((jiffies - start_jiffies) >= HZ) {
+ if (reg16 & PCI_EXP_LNKSTA_LT) {
dev_printk (KERN_ERR, &pdev->dev, "ASPM: Could not configure"
" common clock\n");
i = 0;
@@ -419,9 +445,9 @@ static unsigned int pcie_aspm_check_state(struct pci_dev *pdev,
{
struct pci_dev *child_dev;
- /* If no child, disable the link */
+ /* If no child, ignore the link */
if (list_empty(&pdev->subordinate->devices))
- return 0;
+ return state;
list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) {
/*
@@ -462,6 +488,9 @@ static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state)
int valid = 1;
struct pcie_link_state *link_state = pdev->link_state;
+ /* If no child, disable the link */
+ if (list_empty(&pdev->subordinate->devices))
+ state = 0;
/*
* if the downstream component has pci bridge function, don't do ASPM
* now
@@ -493,20 +522,52 @@ static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state)
link_state->enabled_state = state;
}
+static struct pcie_link_state *get_root_port_link(struct pcie_link_state *link)
+{
+ struct pcie_link_state *root_port_link = link;
+ while (root_port_link->parent)
+ root_port_link = root_port_link->parent;
+ return root_port_link;
+}
+
+/* check the whole hierarchy, and configure each link in the hierarchy */
static void __pcie_aspm_configure_link_state(struct pci_dev *pdev,
unsigned int state)
{
struct pcie_link_state *link_state = pdev->link_state;
+ struct pcie_link_state *root_port_link = get_root_port_link(link_state);
+ struct pcie_link_state *leaf;
- if (link_state->support_state == 0)
- return;
state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1;
- /* state 0 means disabling aspm */
- state = pcie_aspm_check_state(pdev, state);
+ /* check all links who have specific root port link */
+ list_for_each_entry(leaf, &link_list, sibiling) {
+ if (!list_empty(&leaf->children) ||
+ get_root_port_link(leaf) != root_port_link)
+ continue;
+ state = pcie_aspm_check_state(leaf->pdev, state);
+ }
+ /* check root port link too in case it hasn't children */
+ state = pcie_aspm_check_state(root_port_link->pdev, state);
+
if (link_state->enabled_state == state)
return;
- __pcie_aspm_config_link(pdev, state);
+
+ /*
+ * we must change the hierarchy. See comments in
+ * __pcie_aspm_config_link for the order
+ **/
+ if (state & PCIE_LINK_STATE_L1) {
+ list_for_each_entry(leaf, &link_list, sibiling) {
+ if (get_root_port_link(leaf) == root_port_link)
+ __pcie_aspm_config_link(leaf->pdev, state);
+ }
+ } else {
+ list_for_each_entry_reverse(leaf, &link_list, sibiling) {
+ if (get_root_port_link(leaf) == root_port_link)
+ __pcie_aspm_config_link(leaf->pdev, state);
+ }
+ }
}
/*
@@ -570,6 +631,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
unsigned int state;
struct pcie_link_state *link_state;
int error = 0;
+ int blacklist;
if (aspm_disabled || !pdev->is_pcie || pdev->link_state)
return;
@@ -580,29 +642,58 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
if (list_empty(&pdev->subordinate->devices))
goto out;
- if (pcie_aspm_sanity_check(pdev))
- goto out;
+ blacklist = !!pcie_aspm_sanity_check(pdev);
mutex_lock(&aspm_lock);
link_state = kzalloc(sizeof(*link_state), GFP_KERNEL);
if (!link_state)
goto unlock_out;
- pdev->link_state = link_state;
- pcie_aspm_configure_common_clock(pdev);
+ link_state->downstream_has_switch = pcie_aspm_downstream_has_switch(pdev);
+ INIT_LIST_HEAD(&link_state->children);
+ INIT_LIST_HEAD(&link_state->link);
+ if (pdev->bus->self) {/* this is a switch */
+ struct pcie_link_state *parent_link_state;
- pcie_aspm_cap_init(pdev);
+ parent_link_state = pdev->bus->parent->self->link_state;
+ if (!parent_link_state) {
+ kfree(link_state);
+ goto unlock_out;
+ }
+ list_add(&link_state->link, &parent_link_state->children);
+ link_state->parent = parent_link_state;
+ }
- /* config link state to avoid BIOS error */
- state = pcie_aspm_check_state(pdev, policy_to_aspm_state(pdev));
- __pcie_aspm_config_link(pdev, state);
+ pdev->link_state = link_state;
- pcie_check_clock_pm(pdev);
+ if (!blacklist) {
+ pcie_aspm_configure_common_clock(pdev);
+ pcie_aspm_cap_init(pdev);
+ } else {
+ link_state->enabled_state = PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1;
+ link_state->bios_aspm_state = 0;
+ /* Set support state to 0, so we will disable ASPM later */
+ link_state->support_state = 0;
+ }
link_state->pdev = pdev;
list_add(&link_state->sibiling, &link_list);
+ if (link_state->downstream_has_switch) {
+ /*
+ * If link has switch, delay the link config. The leaf link
+ * initialization will config the whole hierarchy. but we must
+ * make sure BIOS doesn't set unsupported link state
+ **/
+ state = pcie_aspm_check_state(pdev, link_state->bios_aspm_state);
+ __pcie_aspm_config_link(pdev, state);
+ } else
+ __pcie_aspm_configure_link_state(pdev,
+ policy_to_aspm_state(pdev));
+
+ pcie_check_clock_pm(pdev, blacklist);
+
unlock_out:
if (error)
free_link_state(pdev);
@@ -635,6 +726,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
/* All functions are removed, so just disable ASPM for the link */
__pcie_aspm_config_one_dev(parent, 0);
list_del(&link_state->sibiling);
+ list_del(&link_state->link);
/* Clock PM is for endpoint device */
free_link_state(parent);
@@ -857,24 +949,15 @@ void pcie_no_aspm(void)
aspm_disabled = 1;
}
-#ifdef CONFIG_ACPI
-#include <acpi/acpi_bus.h>
-#include <linux/pci-acpi.h>
-static void pcie_aspm_platform_init(void)
-{
- pcie_osc_support_set(OSC_ACTIVE_STATE_PWR_SUPPORT|
- OSC_CLOCK_PWR_CAPABILITY_SUPPORT);
-}
-#else
-static inline void pcie_aspm_platform_init(void) { }
-#endif
-
-static int __init pcie_aspm_init(void)
+/**
+ * pcie_aspm_enabled - is PCIe ASPM enabled?
+ *
+ * Returns true if ASPM has not been disabled by the command-line option
+ * pcie_aspm=off.
+ **/
+int pcie_aspm_enabled(void)
{
- if (aspm_disabled)
- return 0;
- pcie_aspm_platform_init();
- return 0;
+ return !aspm_disabled;
}
+EXPORT_SYMBOL(pcie_aspm_enabled);
-fs_initcall(pcie_aspm_init);
diff --git a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c
index 359fe5568df1..eec89b767f9f 100644
--- a/drivers/pci/pcie/portdrv_bus.c
+++ b/drivers/pci/pcie/portdrv_bus.c
@@ -16,14 +16,10 @@
#include "portdrv.h"
static int pcie_port_bus_match(struct device *dev, struct device_driver *drv);
-static int pcie_port_bus_suspend(struct device *dev, pm_message_t state);
-static int pcie_port_bus_resume(struct device *dev);
struct bus_type pcie_port_bus_type = {
.name = "pci_express",
.match = pcie_port_bus_match,
- .suspend = pcie_port_bus_suspend,
- .resume = pcie_port_bus_resume,
};
EXPORT_SYMBOL_GPL(pcie_port_bus_type);
@@ -49,32 +45,12 @@ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
return 1;
}
-static int pcie_port_bus_suspend(struct device *dev, pm_message_t state)
+int pcie_port_bus_register(void)
{
- struct pcie_device *pciedev;
- struct pcie_port_service_driver *driver;
-
- if (!dev || !dev->driver)
- return 0;
-
- pciedev = to_pcie_device(dev);
- driver = to_service_driver(dev->driver);
- if (driver && driver->suspend)
- driver->suspend(pciedev, state);
- return 0;
+ return bus_register(&pcie_port_bus_type);
}
-static int pcie_port_bus_resume(struct device *dev)
+void pcie_port_bus_unregister(void)
{
- struct pcie_device *pciedev;
- struct pcie_port_service_driver *driver;
-
- if (!dev || !dev->driver)
- return 0;
-
- pciedev = to_pcie_device(dev);
- driver = to_service_driver(dev->driver);
- if (driver && driver->resume)
- driver->resume(pciedev);
- return 0;
+ bus_unregister(&pcie_port_bus_type);
}
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 2e091e014829..8b3f8c18032f 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -19,91 +19,15 @@
extern int pcie_mch_quirk; /* MSI-quirk Indicator */
-static int pcie_port_probe_service(struct device *dev)
-{
- struct pcie_device *pciedev;
- struct pcie_port_service_driver *driver;
- int status;
-
- if (!dev || !dev->driver)
- return -ENODEV;
-
- driver = to_service_driver(dev->driver);
- if (!driver || !driver->probe)
- return -ENODEV;
-
- pciedev = to_pcie_device(dev);
- status = driver->probe(pciedev, driver->id_table);
- if (!status) {
- dev_printk(KERN_DEBUG, dev, "service driver %s loaded\n",
- driver->name);
- get_device(dev);
- }
- return status;
-}
-
-static int pcie_port_remove_service(struct device *dev)
-{
- struct pcie_device *pciedev;
- struct pcie_port_service_driver *driver;
-
- if (!dev || !dev->driver)
- return 0;
-
- pciedev = to_pcie_device(dev);
- driver = to_service_driver(dev->driver);
- if (driver && driver->remove) {
- dev_printk(KERN_DEBUG, dev, "unloading service driver %s\n",
- driver->name);
- driver->remove(pciedev);
- put_device(dev);
- }
- return 0;
-}
-
-static void pcie_port_shutdown_service(struct device *dev) {}
-
-static int pcie_port_suspend_service(struct device *dev, pm_message_t state)
-{
- struct pcie_device *pciedev;
- struct pcie_port_service_driver *driver;
-
- if (!dev || !dev->driver)
- return 0;
-
- pciedev = to_pcie_device(dev);
- driver = to_service_driver(dev->driver);
- if (driver && driver->suspend)
- driver->suspend(pciedev, state);
- return 0;
-}
-
-static int pcie_port_resume_service(struct device *dev)
-{
- struct pcie_device *pciedev;
- struct pcie_port_service_driver *driver;
-
- if (!dev || !dev->driver)
- return 0;
-
- pciedev = to_pcie_device(dev);
- driver = to_service_driver(dev->driver);
-
- if (driver && driver->resume)
- driver->resume(pciedev);
- return 0;
-}
-
-/*
- * release_pcie_device
- *
- * Being invoked automatically when device is being removed
- * in response to device_unregister(dev) call.
- * Release all resources being claimed.
+/**
+ * release_pcie_device - free PCI Express port service device structure
+ * @dev: Port service device to release
+ *
+ * Invoked automatically when device is being removed in response to
+ * device_unregister(dev). Release all resources being claimed.
*/
static void release_pcie_device(struct device *dev)
{
- dev_printk(KERN_DEBUG, dev, "free port service\n");
kfree(to_pcie_device(dev));
}
@@ -128,7 +52,16 @@ static int is_msi_quirked(struct pci_dev *dev)
}
return quirk;
}
-
+
+/**
+ * assign_interrupt_mode - choose interrupt mode for PCI Express port services
+ * (INTx, MSI-X, MSI) and set up vectors
+ * @dev: PCI Express port to handle
+ * @vectors: Array of interrupt vectors to populate
+ * @mask: Bitmask of port capabilities returned by get_port_device_capability()
+ *
+ * Return value: Interrupt mode associated with the port
+ */
static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask)
{
int i, pos, nvec, status = -EINVAL;
@@ -150,7 +83,6 @@ static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask)
if (pos) {
struct msix_entry msix_entries[PCIE_PORT_DEVICE_MAXSERVICES] =
{{0, 0}, {0, 1}, {0, 2}, {0, 3}};
- dev_info(&dev->dev, "found MSI-X capability\n");
status = pci_enable_msix(dev, msix_entries, nvec);
if (!status) {
int j = 0;
@@ -165,7 +97,6 @@ static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask)
if (status) {
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
if (pos) {
- dev_info(&dev->dev, "found MSI capability\n");
status = pci_enable_msi(dev);
if (!status) {
interrupt_mode = PCIE_PORT_MSI_MODE;
@@ -177,6 +108,16 @@ static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask)
return interrupt_mode;
}
+/**
+ * get_port_device_capability - discover capabilities of a PCI Express port
+ * @dev: PCI Express port to examine
+ *
+ * The capabilities are read from the port's PCI Express configuration registers
+ * as described in PCI Express Base Specification 1.0a sections 7.8.2, 7.8.9 and
+ * 7.9 - 7.11.
+ *
+ * Return value: Bitmask of discovered port capabilities
+ */
static int get_port_device_capability(struct pci_dev *dev)
{
int services = 0, pos;
@@ -204,6 +145,15 @@ static int get_port_device_capability(struct pci_dev *dev)
return services;
}
+/**
+ * pcie_device_init - initialize PCI Express port service device
+ * @dev: Port service device to initialize
+ * @parent: PCI Express port to associate the service device with
+ * @port_type: Type of the port
+ * @service_type: Type of service to associate with the service device
+ * @irq: Interrupt vector to associate with the service device
+ * @irq_mode: Interrupt mode of the service (INTx, MSI-X, MSI)
+ */
static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev,
int port_type, int service_type, int irq, int irq_mode)
{
@@ -224,11 +174,19 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev,
device->driver = NULL;
device->driver_data = NULL;
device->release = release_pcie_device; /* callback to free pcie dev */
- snprintf(device->bus_id, sizeof(device->bus_id), "%s:pcie%02x",
+ dev_set_name(device, "%s:pcie%02x",
pci_name(parent), get_descriptor_id(port_type, service_type));
device->parent = &parent->dev;
}
+/**
+ * alloc_pcie_device - allocate PCI Express port service device structure
+ * @parent: PCI Express port to associate the service device with
+ * @port_type: Type of the port
+ * @service_type: Type of service to associate with the service device
+ * @irq: Interrupt vector to associate with the service device
+ * @irq_mode: Interrupt mode of the service (INTx, MSI-X, MSI)
+ */
static struct pcie_device* alloc_pcie_device(struct pci_dev *parent,
int port_type, int service_type, int irq, int irq_mode)
{
@@ -239,10 +197,13 @@ static struct pcie_device* alloc_pcie_device(struct pci_dev *parent,
return NULL;
pcie_device_init(parent, device, port_type, service_type, irq,irq_mode);
- dev_printk(KERN_DEBUG, &device->device, "allocate port service\n");
return device;
}
+/**
+ * pcie_port_device_probe - check if device is a PCI Express port
+ * @dev: Device to check
+ */
int pcie_port_device_probe(struct pci_dev *dev)
{
int pos, type;
@@ -260,6 +221,13 @@ int pcie_port_device_probe(struct pci_dev *dev)
return -ENODEV;
}
+/**
+ * pcie_port_device_register - register PCI Express port
+ * @dev: PCI Express port to register
+ *
+ * Allocate the port extension structure and register services associated with
+ * the port.
+ */
int pcie_port_device_register(struct pci_dev *dev)
{
struct pcie_port_device_ext *p_ext;
@@ -323,6 +291,11 @@ static int suspend_iter(struct device *dev, void *data)
return 0;
}
+/**
+ * pcie_port_device_suspend - suspend port services associated with a PCIe port
+ * @dev: PCI Express port to handle
+ * @state: Representation of system power management transition in progress
+ */
int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state)
{
return device_for_each_child(&dev->dev, &state, suspend_iter);
@@ -341,6 +314,10 @@ static int resume_iter(struct device *dev, void *data)
return 0;
}
+/**
+ * pcie_port_device_suspend - resume port services associated with a PCIe port
+ * @dev: PCI Express port to handle
+ */
int pcie_port_device_resume(struct pci_dev *dev)
{
return device_for_each_child(&dev->dev, NULL, resume_iter);
@@ -363,6 +340,13 @@ static int remove_iter(struct device *dev, void *data)
return 0;
}
+/**
+ * pcie_port_device_remove - unregister PCI Express port service devices
+ * @dev: PCI Express port the service devices to unregister are associated with
+ *
+ * Remove PCI Express port service devices associated with given port and
+ * disable MSI-X or MSI for the port.
+ */
void pcie_port_device_remove(struct pci_dev *dev)
{
struct device *device;
@@ -386,16 +370,80 @@ void pcie_port_device_remove(struct pci_dev *dev)
pci_disable_msi(dev);
}
-int pcie_port_bus_register(void)
+/**
+ * pcie_port_probe_service - probe driver for given PCI Express port service
+ * @dev: PCI Express port service device to probe against
+ *
+ * If PCI Express port service driver is registered with
+ * pcie_port_service_register(), this function will be called by the driver core
+ * whenever match is found between the driver and a port service device.
+ */
+static int pcie_port_probe_service(struct device *dev)
{
- return bus_register(&pcie_port_bus_type);
+ struct pcie_device *pciedev;
+ struct pcie_port_service_driver *driver;
+ int status;
+
+ if (!dev || !dev->driver)
+ return -ENODEV;
+
+ driver = to_service_driver(dev->driver);
+ if (!driver || !driver->probe)
+ return -ENODEV;
+
+ pciedev = to_pcie_device(dev);
+ status = driver->probe(pciedev, driver->id_table);
+ if (!status) {
+ dev_printk(KERN_DEBUG, dev, "service driver %s loaded\n",
+ driver->name);
+ get_device(dev);
+ }
+ return status;
}
-void pcie_port_bus_unregister(void)
+/**
+ * pcie_port_remove_service - detach driver from given PCI Express port service
+ * @dev: PCI Express port service device to handle
+ *
+ * If PCI Express port service driver is registered with
+ * pcie_port_service_register(), this function will be called by the driver core
+ * when device_unregister() is called for the port service device associated
+ * with the driver.
+ */
+static int pcie_port_remove_service(struct device *dev)
{
- bus_unregister(&pcie_port_bus_type);
+ struct pcie_device *pciedev;
+ struct pcie_port_service_driver *driver;
+
+ if (!dev || !dev->driver)
+ return 0;
+
+ pciedev = to_pcie_device(dev);
+ driver = to_service_driver(dev->driver);
+ if (driver && driver->remove) {
+ dev_printk(KERN_DEBUG, dev, "unloading service driver %s\n",
+ driver->name);
+ driver->remove(pciedev);
+ put_device(dev);
+ }
+ return 0;
}
+/**
+ * pcie_port_shutdown_service - shut down given PCI Express port service
+ * @dev: PCI Express port service device to handle
+ *
+ * If PCI Express port service driver is registered with
+ * pcie_port_service_register(), this function will be called by the driver core
+ * when device_shutdown() is called for the port service device associated
+ * with the driver.
+ */
+static void pcie_port_shutdown_service(struct device *dev) {}
+
+/**
+ * pcie_port_service_register - register PCI Express port service driver
+ * @new: PCI Express port service driver to register
+ */
int pcie_port_service_register(struct pcie_port_service_driver *new)
{
new->driver.name = (char *)new->name;
@@ -403,15 +451,17 @@ int pcie_port_service_register(struct pcie_port_service_driver *new)
new->driver.probe = pcie_port_probe_service;
new->driver.remove = pcie_port_remove_service;
new->driver.shutdown = pcie_port_shutdown_service;
- new->driver.suspend = pcie_port_suspend_service;
- new->driver.resume = pcie_port_resume_service;
return driver_register(&new->driver);
}
-void pcie_port_service_unregister(struct pcie_port_service_driver *new)
+/**
+ * pcie_port_service_unregister - unregister PCI Express port service driver
+ * @drv: PCI Express port service driver to unregister
+ */
+void pcie_port_service_unregister(struct pcie_port_service_driver *drv)
{
- driver_unregister(&new->driver);
+ driver_unregister(&drv->driver);
}
EXPORT_SYMBOL(pcie_port_service_register);
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index 584422da8d8b..99a914a027f8 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -41,7 +41,6 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev)
{
int retval;
- pci_restore_state(dev);
retval = pci_enable_device(dev);
if (retval)
return retval;
@@ -52,11 +51,18 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev)
#ifdef CONFIG_PM
static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state)
{
- int ret = pcie_port_device_suspend(dev, state);
+ return pcie_port_device_suspend(dev, state);
- if (!ret)
- ret = pcie_portdrv_save_config(dev);
- return ret;
+}
+
+static int pcie_portdrv_suspend_late(struct pci_dev *dev, pm_message_t state)
+{
+ return pci_save_state(dev);
+}
+
+static int pcie_portdrv_resume_early(struct pci_dev *dev)
+{
+ return pci_restore_state(dev);
}
static int pcie_portdrv_resume(struct pci_dev *dev)
@@ -66,6 +72,8 @@ static int pcie_portdrv_resume(struct pci_dev *dev)
}
#else
#define pcie_portdrv_suspend NULL
+#define pcie_portdrv_suspend_late NULL
+#define pcie_portdrv_resume_early NULL
#define pcie_portdrv_resume NULL
#endif
@@ -221,6 +229,7 @@ static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
/* If fatal, restore cfg space for possible link reset at upstream */
if (dev->error_state == pci_channel_io_frozen) {
+ pci_restore_state(dev);
pcie_portdrv_restore_config(dev);
pci_enable_pcie_error_reporting(dev);
}
@@ -283,6 +292,8 @@ static struct pci_driver pcie_portdriver = {
.remove = pcie_portdrv_remove,
.suspend = pcie_portdrv_suspend,
+ .suspend_late = pcie_portdrv_suspend_late,
+ .resume_early = pcie_portdrv_resume_early,
.resume = pcie_portdrv_resume,
.err_handler = &pcie_portdrv_err_handler,
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 5b3f5937ecf5..55ec44a27e89 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -51,12 +51,12 @@ static ssize_t pci_bus_show_cpuaffinity(struct device *dev,
char *buf)
{
int ret;
- cpumask_t cpumask;
+ const struct cpumask *cpumask;
- cpumask = pcibus_to_cpumask(to_pci_bus(dev));
+ cpumask = cpumask_of_pcibus(to_pci_bus(dev));
ret = type?
- cpulist_scnprintf(buf, PAGE_SIZE-2, &cpumask) :
- cpumask_scnprintf(buf, PAGE_SIZE-2, &cpumask);
+ cpulist_scnprintf(buf, PAGE_SIZE-2, cpumask) :
+ cpumask_scnprintf(buf, PAGE_SIZE-2, cpumask);
buf[ret++] = '\n';
buf[ret] = '\0';
return ret;
@@ -135,13 +135,6 @@ static u64 pci_size(u64 base, u64 maxbase, u64 mask)
return size;
}
-enum pci_bar_type {
- pci_bar_unknown, /* Standard PCI BAR probe */
- pci_bar_io, /* An io port BAR */
- pci_bar_mem32, /* A 32-bit memory BAR */
- pci_bar_mem64, /* A 64-bit memory BAR */
-};
-
static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar)
{
if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
@@ -156,11 +149,16 @@ static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar)
return pci_bar_mem32;
}
-/*
- * If the type is not unknown, we assume that the lowest bit is 'enable'.
- * Returns 1 if the BAR was 64-bit and 0 if it was 32-bit.
+/**
+ * pci_read_base - read a PCI BAR
+ * @dev: the PCI device
+ * @type: type of the BAR
+ * @res: resource buffer to be filled in
+ * @pos: BAR position in the config space
+ *
+ * Returns 1 if the BAR is 64-bit, or 0 if 32-bit.
*/
-static int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
+int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
struct resource *res, unsigned int pos)
{
u32 l, sz, mask;
@@ -400,19 +398,17 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
if (!child)
return NULL;
- child->self = bridge;
child->parent = parent;
child->ops = parent->ops;
child->sysdata = parent->sysdata;
child->bus_flags = parent->bus_flags;
- child->bridge = get_device(&bridge->dev);
/* initialize some portions of the bus device, but don't register it
* now as the parent is not properly set up yet. This device will get
* registered later in pci_bus_add_devices()
*/
child->dev.class = &pcibus_class;
- sprintf(child->dev.bus_id, "%04x:%02x", pci_domain_nr(child), busnr);
+ dev_set_name(&child->dev, "%04x:%02x", pci_domain_nr(child), busnr);
/*
* Set up the primary, secondary and subordinate
@@ -422,8 +418,14 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
child->primary = parent->secondary;
child->subordinate = 0xff;
+ if (!bridge)
+ return child;
+
+ child->self = bridge;
+ child->bridge = get_device(&bridge->dev);
+
/* Set up default resource pointers and names.. */
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i];
child->resource[i]->name = child->name;
}
@@ -958,8 +960,12 @@ static void pci_init_capabilities(struct pci_dev *dev)
/* MSI/MSI-X list */
pci_msi_init_pci_dev(dev);
+ /* Buffers for saving PCIe and PCI-X capabilities */
+ pci_allocate_cap_save_buffers(dev);
+
/* Power Management */
pci_pm_init(dev);
+ platform_pci_wakeup_init(dev);
/* Vital Product Data */
pci_vpd_pci22_init(dev);
@@ -1130,7 +1136,7 @@ struct pci_bus * pci_create_bus(struct device *parent,
memset(dev, 0, sizeof(*dev));
dev->parent = parent;
dev->release = pci_release_bus_bridge_dev;
- sprintf(dev->bus_id, "pci%04x:%02x", pci_domain_nr(b), bus);
+ dev_set_name(dev, "pci%04x:%02x", pci_domain_nr(b), bus);
error = device_register(dev);
if (error)
goto dev_reg_err;
@@ -1141,7 +1147,7 @@ struct pci_bus * pci_create_bus(struct device *parent,
b->dev.class = &pcibus_class;
b->dev.parent = b->bridge;
- sprintf(b->dev.bus_id, "%04x:%02x", pci_domain_nr(b), bus);
+ dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus);
error = device_register(&b->dev);
if (error)
goto class_dev_reg_err;
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index e1098c302c45..593bb844b8db 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -252,11 +252,20 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
const struct proc_dir_entry *dp = PDE(inode);
struct pci_dev *dev = dp->data;
struct pci_filp_private *fpriv = file->private_data;
- int ret;
+ int i, ret;
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
+ /* Make sure the caller is mapping a real resource for this device */
+ for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+ if (pci_mmap_fits(dev, i, vma))
+ break;
+ }
+
+ if (i >= PCI_ROM_RESOURCE)
+ return -ENODEV;
+
ret = pci_mmap_page_range(dev, vma,
fpriv->mmap_state,
fpriv->write_combine);
@@ -352,15 +361,16 @@ static int show_device(struct seq_file *m, void *v)
dev->vendor,
dev->device,
dev->irq);
- /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */
- for (i=0; i<7; i++) {
+
+ /* only print standard and ROM resources to preserve compatibility */
+ for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
resource_size_t start, end;
pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
seq_printf(m, "\t%16llx",
(unsigned long long)(start |
(dev->resource[i].flags & PCI_REGION_FLAG_MASK)));
}
- for (i=0; i<7; i++) {
+ for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
resource_size_t start, end;
pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
seq_printf(m, "\t%16llx",
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index ce0985615133..baad093aafe3 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -56,7 +56,7 @@ static void quirk_passive_release(struct pci_dev *dev)
while ((d = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) {
pci_read_config_byte(d, 0x82, &dlc);
if (!(dlc & 1<<1)) {
- dev_err(&d->dev, "PIIX3: Enabling Passive Release\n");
+ dev_info(&d->dev, "PIIX3: Enabling Passive Release\n");
dlc |= 1<<1;
pci_write_config_byte(d, 0x82, dlc);
}
@@ -449,7 +449,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12,
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, quirk_ich4_lpc_acpi);
-static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev)
+static void __devinit ich6_lpc_acpi_gpio(struct pci_dev *dev)
{
u32 region;
@@ -459,20 +459,95 @@ static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev)
pci_read_config_dword(dev, 0x48, &region);
quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH6 GPIO");
}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich6_lpc_acpi);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich6_lpc_acpi);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich6_lpc_acpi);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich6_lpc_acpi);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich6_lpc_acpi);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich6_lpc_acpi);
+
+static void __devinit ich6_lpc_generic_decode(struct pci_dev *dev, unsigned reg, const char *name, int dynsize)
+{
+ u32 val;
+ u32 size, base;
+
+ pci_read_config_dword(dev, reg, &val);
+
+ /* Enabled? */
+ if (!(val & 1))
+ return;
+ base = val & 0xfffc;
+ if (dynsize) {
+ /*
+ * This is not correct. It is 16, 32 or 64 bytes depending on
+ * register D31:F0:ADh bits 5:4.
+ *
+ * But this gets us at least _part_ of it.
+ */
+ size = 16;
+ } else {
+ size = 128;
+ }
+ base &= ~(size-1);
+
+ /* Just print it out for now. We should reserve it after more debugging */
+ dev_info(&dev->dev, "%s PIO at %04x-%04x\n", name, base, base+size-1);
+}
+
+static void __devinit quirk_ich6_lpc(struct pci_dev *dev)
+{
+ /* Shared ACPI/GPIO decode with all ICH6+ */
+ ich6_lpc_acpi_gpio(dev);
+
+ /* ICH6-specific generic IO decode */
+ ich6_lpc_generic_decode(dev, 0x84, "LPC Generic IO decode 1", 0);
+ ich6_lpc_generic_decode(dev, 0x88, "LPC Generic IO decode 2", 1);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc);
+
+static void __devinit ich7_lpc_generic_decode(struct pci_dev *dev, unsigned reg, const char *name)
+{
+ u32 val;
+ u32 mask, base;
+
+ pci_read_config_dword(dev, reg, &val);
+
+ /* Enabled? */
+ if (!(val & 1))
+ return;
+
+ /*
+ * IO base in bits 15:2, mask in bits 23:18, both
+ * are dword-based
+ */
+ base = val & 0xfffc;
+ mask = (val >> 16) & 0xfc;
+ mask |= 3;
+
+ /* Just print it out for now. We should reserve it after more debugging */
+ dev_info(&dev->dev, "%s PIO at %04x (mask %04x)\n", name, base, mask);
+}
+
+/* ICH7-10 has the same common LPC generic IO decode registers */
+static void __devinit quirk_ich7_lpc(struct pci_dev *dev)
+{
+ /* We share the common ACPI/DPIO decode with ICH6 */
+ ich6_lpc_acpi_gpio(dev);
+
+ /* And have 4 ICH7+ generic decodes */
+ ich7_lpc_generic_decode(dev, 0x84, "ICH7 LPC Generic IO decode 1");
+ ich7_lpc_generic_decode(dev, 0x88, "ICH7 LPC Generic IO decode 2");
+ ich7_lpc_generic_decode(dev, 0x8c, "ICH7 LPC Generic IO decode 3");
+ ich7_lpc_generic_decode(dev, 0x90, "ICH7 LPC Generic IO decode 4");
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich7_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich7_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich7_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich7_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich7_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich7_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1, quirk_ich7_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_4, quirk_ich7_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, quirk_ich7_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_4, quirk_ich7_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_7, quirk_ich7_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_8, quirk_ich7_lpc);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_1, quirk_ich7_lpc);
/*
* VIA ACPI: One IO region pointed to by longword at
@@ -2074,11 +2149,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4375,
#endif /* CONFIG_PCI_MSI */
-static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end)
+static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
+ struct pci_fixup *end)
{
while (f < end) {
if ((f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) &&
- (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
+ (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) {
dev_dbg(&dev->dev, "calling %pF\n", f->hook);
f->hook(dev);
}
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index ea979f2bc6db..704608945780 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -536,9 +536,8 @@ static void pci_bus_dump_res(struct pci_bus *bus)
if (!res)
continue;
- printk(KERN_INFO "bus: %02x index %x %s: %pR\n",
- bus->number, i,
- (res->flags & IORESOURCE_IO) ? "io port" : "mmio", res);
+ dev_printk(KERN_DEBUG, &bus->dev, "resource %d %s %pR\n", i,
+ (res->flags & IORESOURCE_IO) ? "io: " : "mem:", res);
}
}
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 2dbd96cce2d8..32e8d88a4619 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -26,11 +26,13 @@
#include "pci.h"
-void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
+void pci_update_resource(struct pci_dev *dev, int resno)
{
struct pci_bus_region region;
u32 new, check, mask;
int reg;
+ enum pci_bar_type type;
+ struct resource *res = dev->resource + resno;
/*
* Ignore resources for unimplemented BARs and unused resource slots
@@ -61,17 +63,13 @@ void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
else
mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
- if (resno < 6) {
- reg = PCI_BASE_ADDRESS_0 + 4 * resno;
- } else if (resno == PCI_ROM_RESOURCE) {
+ reg = pci_resource_bar(dev, resno, &type);
+ if (!reg)
+ return;
+ if (type != pci_bar_unknown) {
if (!(res->flags & IORESOURCE_ROM_ENABLE))
return;
new |= PCI_ROM_ADDRESS_ENABLE;
- reg = dev->rom_base_reg;
- } else {
- /* Hmm, non-standard resource. */
-
- return; /* kill uninitialised var warning */
}
pci_write_config_dword(dev, reg, new);
@@ -134,7 +132,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
align = resource_alignment(res);
if (!align) {
- dev_err(&dev->dev, "BAR %d: can't allocate resource (bogus "
+ dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus "
"alignment) %pR flags %#lx\n",
resno, res, res->flags);
return -EINVAL;
@@ -157,12 +155,12 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
}
if (ret) {
- dev_err(&dev->dev, "BAR %d: can't allocate %s resource %pR\n",
+ dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n",
resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res);
} else {
res->flags &= ~IORESOURCE_STARTALIGN;
if (resno < PCI_BRIDGE_RESOURCES)
- pci_update_resource(dev, res, resno);
+ pci_update_resource(dev, resno);
}
return ret;
@@ -197,7 +195,7 @@ int pci_assign_resource_fixed(struct pci_dev *dev, int resno)
dev_err(&dev->dev, "BAR %d: can't allocate %s resource %pR\n",
resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res);
} else if (resno < PCI_BRIDGE_RESOURCES) {
- pci_update_resource(dev, res, resno);
+ pci_update_resource(dev, resno);
}
return ret;
diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c
index 645d7a60e412..ec22284eed30 100644
--- a/drivers/pci/syscall.c
+++ b/drivers/pci/syscall.c
@@ -14,10 +14,8 @@
#include <asm/uaccess.h>
#include "pci.h"
-asmlinkage long
-sys_pciconfig_read(unsigned long bus, unsigned long dfn,
- unsigned long off, unsigned long len,
- void __user *buf)
+SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn,
+ unsigned long, off, unsigned long, len, void __user *, buf)
{
struct pci_dev *dev;
u8 byte;
@@ -86,10 +84,8 @@ error:
return err;
}
-asmlinkage long
-sys_pciconfig_write(unsigned long bus, unsigned long dfn,
- unsigned long off, unsigned long len,
- void __user *buf)
+SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn,
+ unsigned long, off, unsigned long, len, void __user *, buf)
{
struct pci_dev *dev;
u8 byte;
diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c
index a34284b1482a..d187ba4c5e0e 100644
--- a/drivers/pcmcia/electra_cf.c
+++ b/drivers/pcmcia/electra_cf.c
@@ -297,7 +297,7 @@ static int __devinit electra_cf_probe(struct of_device *ofdev,
goto fail3;
}
- dev_info(device, "at mem 0x%lx io 0x%lx irq %d\n",
+ dev_info(device, "at mem 0x%lx io 0x%llx irq %d\n",
cf->mem_phys, io.start, cf->irq);
cf->active = 1;
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
new file mode 100644
index 000000000000..9652c3fe7f5e
--- /dev/null
+++ b/drivers/platform/Kconfig
@@ -0,0 +1,5 @@
+# drivers/platform/Kconfig
+
+if X86
+source "drivers/platform/x86/Kconfig"
+endif
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
new file mode 100644
index 000000000000..782953ae4c03
--- /dev/null
+++ b/drivers/platform/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for linux/drivers/platform
+#
+
+obj-$(CONFIG_X86) += x86/
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
new file mode 100644
index 000000000000..1a266d4ab5f1
--- /dev/null
+++ b/drivers/platform/x86/Kconfig
@@ -0,0 +1,398 @@
+#
+# X86 Platform Specific Drivers
+#
+
+menuconfig X86_PLATFORM_DEVICES
+ bool "X86 Platform Specific Device Drivers"
+ default y
+ ---help---
+ Say Y here to get to see options for device drivers for various
+ x86 platforms, including vendor-specific laptop extension drivers.
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
+
+if X86_PLATFORM_DEVICES
+
+config ACER_WMI
+ tristate "Acer WMI Laptop Extras (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ depends on ACPI
+ depends on LEDS_CLASS
+ depends on NEW_LEDS
+ depends on BACKLIGHT_CLASS_DEVICE
+ depends on SERIO_I8042
+ depends on RFKILL
+ select ACPI_WMI
+ ---help---
+ This is a driver for newer Acer (and Wistron) laptops. It adds
+ wireless radio and bluetooth control, and on some laptops,
+ exposes the mail LED and LCD backlight.
+
+ For more information about this driver see
+ <file:Documentation/laptops/acer-wmi.txt>
+
+ If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
+ here.
+
+config ASUS_LAPTOP
+ tristate "Asus Laptop Extras (EXPERIMENTAL)"
+ depends on ACPI
+ depends on EXPERIMENTAL && !ACPI_ASUS
+ depends on LEDS_CLASS
+ depends on NEW_LEDS
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This is the new Linux driver for Asus laptops. It may also support some
+ MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
+ standard ACPI events that go through /proc/acpi/events. It also adds
+ support for video output switching, LCD backlight control, Bluetooth and
+ Wlan control, and most importantly, allows you to blink those fancy LEDs.
+
+ For more information and a userspace daemon for handling the extra
+ buttons see <http://acpi4asus.sf.net/>.
+
+ If you have an ACPI-compatible ASUS laptop, say Y or M here.
+
+config DELL_LAPTOP
+ tristate "Dell Laptop Extras (EXPERIMENTAL)"
+ depends on X86
+ depends on DCDBAS
+ depends on EXPERIMENTAL
+ depends on BACKLIGHT_CLASS_DEVICE
+ depends on RFKILL
+ default n
+ ---help---
+ This driver adds support for rfkill and backlight control to Dell
+ laptops.
+
+config FUJITSU_LAPTOP
+ tristate "Fujitsu Laptop Extras"
+ depends on ACPI
+ depends on INPUT
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This is a driver for laptops built by Fujitsu:
+
+ * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks
+ * Possibly other Fujitsu laptop models
+ * Tested with S6410 and S7020
+
+ It adds support for LCD brightness control and some hotkeys.
+
+ If you have a Fujitsu laptop, say Y or M here.
+
+config FUJITSU_LAPTOP_DEBUG
+ bool "Verbose debug mode for Fujitsu Laptop Extras"
+ depends on FUJITSU_LAPTOP
+ default n
+ ---help---
+ Enables extra debug output from the fujitsu extras driver, at the
+ expense of a slight increase in driver size.
+
+ If you are not sure, say N here.
+
+config TC1100_WMI
+ tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)"
+ depends on !X86_64
+ depends on EXPERIMENTAL
+ depends on ACPI
+ select ACPI_WMI
+ ---help---
+ This is a driver for the WMI extensions (wireless and bluetooth power
+ control) of the HP Compaq TC1100 tablet.
+
+config HP_WMI
+ tristate "HP WMI extras"
+ depends on ACPI_WMI
+ depends on INPUT
+ depends on RFKILL
+ help
+ Say Y here if you want to support WMI-based hotkeys on HP laptops and
+ to read data from WMI such as docking or ambient light sensor state.
+
+ To compile this driver as a module, choose M here: the module will
+ be called hp-wmi.
+
+config MSI_LAPTOP
+ tristate "MSI Laptop Extras"
+ depends on ACPI
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This is a driver for laptops built by MSI (MICRO-STAR
+ INTERNATIONAL):
+
+ MSI MegaBook S270 (MS-1013)
+ Cytron/TCM/Medion/Tchibo MD96100/SAM2000
+
+ It adds support for Bluetooth, WLAN and LCD brightness control.
+
+ More information about this driver is available at
+ <http://0pointer.de/lennart/tchibo.html>.
+
+ If you have an MSI S270 laptop, say Y or M here.
+
+config PANASONIC_LAPTOP
+ tristate "Panasonic Laptop Extras"
+ depends on INPUT && ACPI
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This driver adds support for access to backlight control and hotkeys
+ on Panasonic Let's Note laptops.
+
+ If you have a Panasonic Let's note laptop (such as the R1(N variant),
+ R2, R3, R5, T2, W2 and Y2 series), say Y.
+
+config COMPAL_LAPTOP
+ tristate "Compal Laptop Extras"
+ depends on ACPI
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This is a driver for laptops built by Compal:
+
+ Compal FL90/IFL90
+ Compal FL91/IFL91
+ Compal FL92/JFL92
+ Compal FT00/IFT00
+
+ It adds support for Bluetooth, WLAN and LCD brightness control.
+
+ If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here.
+
+config SONY_LAPTOP
+ tristate "Sony Laptop Extras"
+ depends on ACPI
+ select BACKLIGHT_CLASS_DEVICE
+ depends on INPUT
+ ---help---
+ This mini-driver drives the SNC and SPIC devices present in the ACPI
+ BIOS of the Sony Vaio laptops.
+
+ It gives access to some extra laptop functionalities like Bluetooth,
+ screen brightness control, Fn keys and allows powering on/off some
+ devices.
+
+ Read <file:Documentation/laptops/sony-laptop.txt> for more information.
+
+config SONYPI_COMPAT
+ bool "Sonypi compatibility"
+ depends on SONY_LAPTOP
+ ---help---
+ Build the sonypi driver compatibility code into the sony-laptop driver.
+
+config THINKPAD_ACPI
+ tristate "ThinkPad ACPI Laptop Extras"
+ depends on ACPI
+ select BACKLIGHT_LCD_SUPPORT
+ select BACKLIGHT_CLASS_DEVICE
+ select HWMON
+ select NVRAM
+ select INPUT
+ select NEW_LEDS
+ select LEDS_CLASS
+ select NET
+ select RFKILL
+ ---help---
+ This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
+ support for Fn-Fx key combinations, Bluetooth control, video
+ output switching, ThinkLight control, UltraBay eject and more.
+ For more information about this driver see
+ <file:Documentation/laptops/thinkpad-acpi.txt> and
+ <http://ibm-acpi.sf.net/> .
+
+ This driver was formerly known as ibm-acpi.
+
+ If you have an IBM or Lenovo ThinkPad laptop, say Y or M here.
+
+config THINKPAD_ACPI_DEBUGFACILITIES
+ bool "Maintainer debug facilities"
+ depends on THINKPAD_ACPI
+ default n
+ ---help---
+ Enables extra stuff in the thinkpad-acpi which is completely useless
+ for normal use. Read the driver source to find out what it does.
+
+ Say N here, unless you were told by a kernel maintainer to do
+ otherwise.
+
+config THINKPAD_ACPI_DEBUG
+ bool "Verbose debug mode"
+ depends on THINKPAD_ACPI
+ default n
+ ---help---
+ Enables extra debugging information, at the expense of a slightly
+ increase in driver size.
+
+ If you are not sure, say N here.
+
+config THINKPAD_ACPI_DOCK
+ bool "Legacy Docking Station Support"
+ depends on THINKPAD_ACPI
+ depends on ACPI_DOCK=n
+ default n
+ ---help---
+ Allows the thinkpad_acpi driver to handle docking station events.
+ This support was made obsolete by the generic ACPI docking station
+ support (CONFIG_ACPI_DOCK). It will allow locking and removing the
+ laptop from the docking station, but will not properly connect PCI
+ devices.
+
+ If you are not sure, say N here.
+
+config THINKPAD_ACPI_BAY
+ bool "Legacy Removable Bay Support"
+ depends on THINKPAD_ACPI
+ default y
+ ---help---
+ Allows the thinkpad_acpi driver to handle removable bays. It will
+ electrically disable the device in the bay, and also generate
+ notifications when the bay lever is ejected or inserted.
+
+ If you are not sure, say Y here.
+
+config THINKPAD_ACPI_VIDEO
+ bool "Video output control support"
+ depends on THINKPAD_ACPI
+ default y
+ ---help---
+ Allows the thinkpad_acpi driver to provide an interface to control
+ the various video output ports.
+
+ This feature often won't work well, depending on ThinkPad model,
+ display state, video output devices in use, whether there is a X
+ server running, phase of the moon, and the current mood of
+ Schroedinger's cat. If you can use X.org's RandR to control
+ your ThinkPad's video output ports instead of this feature,
+ don't think twice: do it and say N here to save some memory.
+
+ If you are not sure, say Y here.
+
+config THINKPAD_ACPI_HOTKEY_POLL
+ bool "Support NVRAM polling for hot keys"
+ depends on THINKPAD_ACPI
+ default y
+ ---help---
+ Some thinkpad models benefit from NVRAM polling to detect a few of
+ the hot key press events. If you know your ThinkPad model does not
+ need to do NVRAM polling to support any of the hot keys you use,
+ unselecting this option will save about 1kB of memory.
+
+ ThinkPads T40 and newer, R52 and newer, and X31 and newer are
+ unlikely to need NVRAM polling in their latest BIOS versions.
+
+ NVRAM polling can detect at most the following keys: ThinkPad/Access
+ IBM, Zoom, Switch Display (fn+F7), ThinkLight, Volume up/down/mute,
+ Brightness up/down, Display Expand (fn+F8), Hibernate (fn+F12).
+
+ If you are not sure, say Y here. The driver enables polling only if
+ it is strictly necessary to do so.
+
+config INTEL_MENLOW
+ tristate "Thermal Management driver for Intel menlow platform"
+ depends on ACPI_THERMAL
+ select THERMAL
+ ---help---
+ ACPI thermal management enhancement driver on
+ Intel Menlow platform.
+
+ If unsure, say N.
+
+config EEEPC_LAPTOP
+ tristate "Eee PC Hotkey Driver (EXPERIMENTAL)"
+ depends on ACPI
+ depends on EXPERIMENTAL
+ select BACKLIGHT_CLASS_DEVICE
+ select HWMON
+ select RFKILL
+ ---help---
+ This driver supports the Fn-Fx keys on Eee PC laptops.
+ It also adds the ability to switch camera/wlan on/off.
+
+ If you have an Eee PC laptop, say Y or M here.
+
+
+config ACPI_WMI
+ tristate "WMI (EXPERIMENTAL)"
+ depends on ACPI
+ depends on EXPERIMENTAL
+ help
+ This driver adds support for the ACPI-WMI (Windows Management
+ Instrumentation) mapper device (PNP0C14) found on some systems.
+
+ ACPI-WMI is a proprietary extension to ACPI to expose parts of the
+ ACPI firmware to userspace - this is done through various vendor
+ defined methods and data blocks in a PNP0C14 device, which are then
+ made available for userspace to call.
+
+ The implementation of this in Linux currently only exposes this to
+ other kernel space drivers.
+
+ This driver is a required dependency to build the firmware specific
+ drivers needed on many machines, including Acer and HP laptops.
+
+ It is safe to enable this driver even if your DSDT doesn't define
+ any ACPI-WMI devices.
+
+config ACPI_ASUS
+ tristate "ASUS/Medion Laptop Extras"
+ depends on ACPI
+ select BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This driver provides support for extra features of ACPI-compatible
+ ASUS laptops. As some of Medion laptops are made by ASUS, it may also
+ support some Medion laptops (such as 9675 for example). It makes all
+ the extra buttons generate standard ACPI events that go through
+ /proc/acpi/events, and (on some models) adds support for changing the
+ display brightness and output, switching the LCD backlight on and off,
+ and most importantly, allows you to blink those fancy LEDs intended
+ for reporting mail and wireless status.
+
+ Note: display switching code is currently considered EXPERIMENTAL,
+ toying with these values may even lock your machine.
+
+ All settings are changed via /proc/acpi/asus directory entries. Owner
+ and group for these entries can be set with asus_uid and asus_gid
+ parameters.
+
+ More information and a userspace daemon for handling the extra buttons
+ at <http://sourceforge.net/projects/acpi4asus/>.
+
+ If you have an ACPI-compatible ASUS laptop, say Y or M here. This
+ driver is still under development, so if your laptop is unsupported or
+ something works not quite as expected, please use the mailing list
+ available on the above page (acpi4asus-user@lists.sourceforge.net).
+
+ NOTE: This driver is deprecated and will probably be removed soon,
+ use asus-laptop instead.
+
+config ACPI_TOSHIBA
+ tristate "Toshiba Laptop Extras"
+ depends on ACPI
+ depends on INPUT
+ select INPUT_POLLDEV
+ select NET
+ select RFKILL
+ select BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This driver adds support for access to certain system settings
+ on "legacy free" Toshiba laptops. These laptops can be recognized by
+ their lack of a BIOS setup menu and APM support.
+
+ On these machines, all system configuration is handled through the
+ ACPI. This driver is required for access to controls not covered
+ by the general ACPI drivers, such as LCD brightness, video output,
+ etc.
+
+ This driver differs from the non-ACPI Toshiba laptop driver (located
+ under "Processor type and features") in several aspects.
+ Configuration is accessed by reading and writing text files in the
+ /proc tree instead of by program interface to /dev. Furthermore, no
+ power management functions are exposed, as those are handled by the
+ general ACPI drivers.
+
+ More information about this driver is available at
+ <http://memebeam.org/toys/ToshibaAcpiDriver>.
+
+ If you have a legacy free Toshiba laptop (such as the Libretto L1
+ series), say Y.
+endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
new file mode 100644
index 000000000000..e29065120be9
--- /dev/null
+++ b/drivers/platform/x86/Makefile
@@ -0,0 +1,20 @@
+#
+# Makefile for linux/drivers/platform/x86
+# x86 Platform-Specific Drivers
+#
+obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
+obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
+obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
+obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
+obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
+obj-$(CONFIG_ACER_WMI) += acer-wmi.o
+obj-$(CONFIG_HP_WMI) += hp-wmi.o
+obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
+obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
+obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
+obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
+obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
+obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
+obj-$(CONFIG_ACPI_WMI) += wmi.o
+obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
+obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
diff --git a/drivers/misc/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 94c9f911824e..94c9f911824e 100644
--- a/drivers/misc/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
diff --git a/drivers/misc/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 8fb8b3591048..8fb8b3591048 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
diff --git a/drivers/acpi/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
index 1e74988c7b2d..1e74988c7b2d 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/platform/x86/asus_acpi.c
diff --git a/drivers/misc/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index 11003bba10d3..11003bba10d3 100644
--- a/drivers/misc/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
new file mode 100644
index 000000000000..16e11c2ee19a
--- /dev/null
+++ b/drivers/platform/x86/dell-laptop.c
@@ -0,0 +1,436 @@
+/*
+ * Driver for Dell laptop extras
+ *
+ * Copyright (c) Red Hat <mjg@redhat.com>
+ *
+ * Based on documentation in the libsmbios package, Copyright (C) 2005 Dell
+ * Inc.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/dmi.h>
+#include <linux/io.h>
+#include <linux/rfkill.h>
+#include <linux/power_supply.h>
+#include <linux/acpi.h>
+#include "../../firmware/dcdbas.h"
+
+#define BRIGHTNESS_TOKEN 0x7d
+
+/* This structure will be modified by the firmware when we enter
+ * system management mode, hence the volatiles */
+
+struct calling_interface_buffer {
+ u16 class;
+ u16 select;
+ volatile u32 input[4];
+ volatile u32 output[4];
+} __packed;
+
+struct calling_interface_token {
+ u16 tokenID;
+ u16 location;
+ union {
+ u16 value;
+ u16 stringlength;
+ };
+};
+
+struct calling_interface_structure {
+ struct dmi_header header;
+ u16 cmdIOAddress;
+ u8 cmdIOCode;
+ u32 supportedCmds;
+ struct calling_interface_token tokens[];
+} __packed;
+
+static int da_command_address;
+static int da_command_code;
+static int da_num_tokens;
+static struct calling_interface_token *da_tokens;
+
+static struct backlight_device *dell_backlight_device;
+static struct rfkill *wifi_rfkill;
+static struct rfkill *bluetooth_rfkill;
+static struct rfkill *wwan_rfkill;
+
+static const struct dmi_system_id __initdata dell_device_table[] = {
+ {
+ .ident = "Dell laptop",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
+ },
+ },
+ { }
+};
+
+static void parse_da_table(const struct dmi_header *dm)
+{
+ /* Final token is a terminator, so we don't want to copy it */
+ int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1;
+ struct calling_interface_structure *table =
+ container_of(dm, struct calling_interface_structure, header);
+
+ /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least
+ 6 bytes of entry */
+
+ if (dm->length < 17)
+ return;
+
+ da_command_address = table->cmdIOAddress;
+ da_command_code = table->cmdIOCode;
+
+ da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) *
+ sizeof(struct calling_interface_token),
+ GFP_KERNEL);
+
+ if (!da_tokens)
+ return;
+
+ memcpy(da_tokens+da_num_tokens, table->tokens,
+ sizeof(struct calling_interface_token) * tokens);
+
+ da_num_tokens += tokens;
+}
+
+static void find_tokens(const struct dmi_header *dm)
+{
+ switch (dm->type) {
+ case 0xd4: /* Indexed IO */
+ break;
+ case 0xd5: /* Protected Area Type 1 */
+ break;
+ case 0xd6: /* Protected Area Type 2 */
+ break;
+ case 0xda: /* Calling interface */
+ parse_da_table(dm);
+ break;
+ }
+}
+
+static int find_token_location(int tokenid)
+{
+ int i;
+ for (i = 0; i < da_num_tokens; i++) {
+ if (da_tokens[i].tokenID == tokenid)
+ return da_tokens[i].location;
+ }
+
+ return -1;
+}
+
+static struct calling_interface_buffer *
+dell_send_request(struct calling_interface_buffer *buffer, int class,
+ int select)
+{
+ struct smi_cmd command;
+
+ command.magic = SMI_CMD_MAGIC;
+ command.command_address = da_command_address;
+ command.command_code = da_command_code;
+ command.ebx = virt_to_phys(buffer);
+ command.ecx = 0x42534931;
+
+ buffer->class = class;
+ buffer->select = select;
+
+ dcdbas_smi_request(&command);
+
+ return buffer;
+}
+
+/* Derived from information in DellWirelessCtl.cpp:
+ Class 17, select 11 is radio control. It returns an array of 32-bit values.
+
+ result[0]: return code
+ result[1]:
+ Bit 0: Hardware switch supported
+ Bit 1: Wifi locator supported
+ Bit 2: Wifi is supported
+ Bit 3: Bluetooth is supported
+ Bit 4: WWAN is supported
+ Bit 5: Wireless keyboard supported
+ Bits 6-7: Reserved
+ Bit 8: Wifi is installed
+ Bit 9: Bluetooth is installed
+ Bit 10: WWAN is installed
+ Bits 11-15: Reserved
+ Bit 16: Hardware switch is on
+ Bit 17: Wifi is blocked
+ Bit 18: Bluetooth is blocked
+ Bit 19: WWAN is blocked
+ Bits 20-31: Reserved
+ result[2]: NVRAM size in bytes
+ result[3]: NVRAM format version number
+*/
+
+static int dell_rfkill_set(int radio, enum rfkill_state state)
+{
+ struct calling_interface_buffer buffer;
+ int disable = (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1;
+
+ memset(&buffer, 0, sizeof(struct calling_interface_buffer));
+ buffer.input[0] = (1 | (radio<<8) | (disable << 16));
+ dell_send_request(&buffer, 17, 11);
+
+ return 0;
+}
+
+static int dell_wifi_set(void *data, enum rfkill_state state)
+{
+ return dell_rfkill_set(1, state);
+}
+
+static int dell_bluetooth_set(void *data, enum rfkill_state state)
+{
+ return dell_rfkill_set(2, state);
+}
+
+static int dell_wwan_set(void *data, enum rfkill_state state)
+{
+ return dell_rfkill_set(3, state);
+}
+
+static int dell_rfkill_get(int bit, enum rfkill_state *state)
+{
+ struct calling_interface_buffer buffer;
+ int status;
+ int new_state = RFKILL_STATE_HARD_BLOCKED;
+
+ memset(&buffer, 0, sizeof(struct calling_interface_buffer));
+ dell_send_request(&buffer, 17, 11);
+ status = buffer.output[1];
+
+ if (status & (1<<16))
+ new_state = RFKILL_STATE_SOFT_BLOCKED;
+
+ if (status & (1<<bit))
+ *state = new_state;
+ else
+ *state = RFKILL_STATE_UNBLOCKED;
+
+ return 0;
+}
+
+static int dell_wifi_get(void *data, enum rfkill_state *state)
+{
+ return dell_rfkill_get(17, state);
+}
+
+static int dell_bluetooth_get(void *data, enum rfkill_state *state)
+{
+ return dell_rfkill_get(18, state);
+}
+
+static int dell_wwan_get(void *data, enum rfkill_state *state)
+{
+ return dell_rfkill_get(19, state);
+}
+
+static int dell_setup_rfkill(void)
+{
+ struct calling_interface_buffer buffer;
+ int status;
+ int ret;
+
+ memset(&buffer, 0, sizeof(struct calling_interface_buffer));
+ dell_send_request(&buffer, 17, 11);
+ status = buffer.output[1];
+
+ if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
+ wifi_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WLAN);
+ if (!wifi_rfkill)
+ goto err_wifi;
+ wifi_rfkill->name = "dell-wifi";
+ wifi_rfkill->toggle_radio = dell_wifi_set;
+ wifi_rfkill->get_state = dell_wifi_get;
+ ret = rfkill_register(wifi_rfkill);
+ if (ret)
+ goto err_wifi;
+ }
+
+ if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) {
+ bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH);
+ if (!bluetooth_rfkill)
+ goto err_bluetooth;
+ bluetooth_rfkill->name = "dell-bluetooth";
+ bluetooth_rfkill->toggle_radio = dell_bluetooth_set;
+ bluetooth_rfkill->get_state = dell_bluetooth_get;
+ ret = rfkill_register(bluetooth_rfkill);
+ if (ret)
+ goto err_bluetooth;
+ }
+
+ if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) {
+ wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN);
+ if (!wwan_rfkill)
+ goto err_wwan;
+ wwan_rfkill->name = "dell-wwan";
+ wwan_rfkill->toggle_radio = dell_wwan_set;
+ wwan_rfkill->get_state = dell_wwan_get;
+ ret = rfkill_register(wwan_rfkill);
+ if (ret)
+ goto err_wwan;
+ }
+
+ return 0;
+err_wwan:
+ if (wwan_rfkill)
+ rfkill_free(wwan_rfkill);
+ if (bluetooth_rfkill) {
+ rfkill_unregister(bluetooth_rfkill);
+ bluetooth_rfkill = NULL;
+ }
+err_bluetooth:
+ if (bluetooth_rfkill)
+ rfkill_free(bluetooth_rfkill);
+ if (wifi_rfkill) {
+ rfkill_unregister(wifi_rfkill);
+ wifi_rfkill = NULL;
+ }
+err_wifi:
+ if (wifi_rfkill)
+ rfkill_free(wifi_rfkill);
+
+ return ret;
+}
+
+static int dell_send_intensity(struct backlight_device *bd)
+{
+ struct calling_interface_buffer buffer;
+
+ memset(&buffer, 0, sizeof(struct calling_interface_buffer));
+ buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN);
+ buffer.input[1] = bd->props.brightness;
+
+ if (buffer.input[0] == -1)
+ return -ENODEV;
+
+ if (power_supply_is_system_supplied() > 0)
+ dell_send_request(&buffer, 1, 2);
+ else
+ dell_send_request(&buffer, 1, 1);
+
+ return 0;
+}
+
+static int dell_get_intensity(struct backlight_device *bd)
+{
+ struct calling_interface_buffer buffer;
+
+ memset(&buffer, 0, sizeof(struct calling_interface_buffer));
+ buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN);
+
+ if (buffer.input[0] == -1)
+ return -ENODEV;
+
+ if (power_supply_is_system_supplied() > 0)
+ dell_send_request(&buffer, 0, 2);
+ else
+ dell_send_request(&buffer, 0, 1);
+
+ return buffer.output[1];
+}
+
+static struct backlight_ops dell_ops = {
+ .get_brightness = dell_get_intensity,
+ .update_status = dell_send_intensity,
+};
+
+static int __init dell_init(void)
+{
+ struct calling_interface_buffer buffer;
+ int max_intensity = 0;
+ int ret;
+
+ if (!dmi_check_system(dell_device_table))
+ return -ENODEV;
+
+ dmi_walk(find_tokens);
+
+ if (!da_tokens) {
+ printk(KERN_INFO "dell-laptop: Unable to find dmi tokens\n");
+ return -ENODEV;
+ }
+
+ ret = dell_setup_rfkill();
+
+ if (ret) {
+ printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n");
+ goto out;
+ }
+
+#ifdef CONFIG_ACPI
+ /* In the event of an ACPI backlight being available, don't
+ * register the platform controller.
+ */
+ if (acpi_video_backlight_support())
+ return 0;
+#endif
+
+ memset(&buffer, 0, sizeof(struct calling_interface_buffer));
+ buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN);
+
+ if (buffer.input[0] != -1) {
+ dell_send_request(&buffer, 0, 2);
+ max_intensity = buffer.output[3];
+ }
+
+ if (max_intensity) {
+ dell_backlight_device = backlight_device_register(
+ "dell_backlight",
+ NULL, NULL,
+ &dell_ops);
+
+ if (IS_ERR(dell_backlight_device)) {
+ ret = PTR_ERR(dell_backlight_device);
+ dell_backlight_device = NULL;
+ goto out;
+ }
+
+ dell_backlight_device->props.max_brightness = max_intensity;
+ dell_backlight_device->props.brightness =
+ dell_get_intensity(dell_backlight_device);
+ backlight_update_status(dell_backlight_device);
+ }
+
+ return 0;
+out:
+ if (wifi_rfkill)
+ rfkill_unregister(wifi_rfkill);
+ if (bluetooth_rfkill)
+ rfkill_unregister(bluetooth_rfkill);
+ if (wwan_rfkill)
+ rfkill_unregister(wwan_rfkill);
+ kfree(da_tokens);
+ return ret;
+}
+
+static void __exit dell_exit(void)
+{
+ backlight_device_unregister(dell_backlight_device);
+ if (wifi_rfkill)
+ rfkill_unregister(wifi_rfkill);
+ if (bluetooth_rfkill)
+ rfkill_unregister(bluetooth_rfkill);
+ if (wwan_rfkill)
+ rfkill_unregister(wwan_rfkill);
+}
+
+module_init(dell_init);
+module_exit(dell_exit);
+
+MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
+MODULE_DESCRIPTION("Dell laptop driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*");
diff --git a/drivers/misc/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 02fe2b8b8939..9d93cb971e59 100644
--- a/drivers/misc/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -90,7 +90,7 @@ enum {
};
static const char *cm_getv[] = {
- "WLDG", NULL, NULL, NULL,
+ "WLDG", "BTHG", NULL, NULL,
"CAMG", NULL, NULL, NULL,
NULL, "PBLG", NULL, NULL,
"CFVG", NULL, NULL, NULL,
@@ -99,7 +99,7 @@ static const char *cm_getv[] = {
};
static const char *cm_setv[] = {
- "WLDS", NULL, NULL, NULL,
+ "WLDS", "BTHS", NULL, NULL,
"CAMS", NULL, NULL, NULL,
"SDSP", "PBLS", "HDPS", NULL,
"CFVS", NULL, NULL, NULL,
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index a7dd3e9fb79d..65dc41540c62 100644
--- a/drivers/misc/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -3,6 +3,7 @@
/*
Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
Copyright (C) 2008 Peter Gruber <nokos@gmx.net>
+ Copyright (C) 2008 Tony Vroon <tony@linx.net>
Based on earlier work:
Copyright (C) 2003 Shane Spencer <shane@bogomip.com>
Adrian Yee <brewt-fujitsu@brewt.org>
@@ -65,8 +66,11 @@
#include <linux/kfifo.h>
#include <linux/video_output.h>
#include <linux/platform_device.h>
+#ifdef CONFIG_LEDS_CLASS
+#include <linux/leds.h>
+#endif
-#define FUJITSU_DRIVER_VERSION "0.4.3"
+#define FUJITSU_DRIVER_VERSION "0.5.0"
#define FUJITSU_LCD_N_LEVELS 8
@@ -83,6 +87,24 @@
#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86
#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
+/* FUNC interface - command values */
+#define FUNC_RFKILL 0x1000
+#define FUNC_LEDS 0x1001
+#define FUNC_BUTTONS 0x1002
+#define FUNC_BACKLIGHT 0x1004
+
+/* FUNC interface - responses */
+#define UNSUPPORTED_CMD 0x80000000
+
+#ifdef CONFIG_LEDS_CLASS
+/* FUNC interface - LED control */
+#define FUNC_LED_OFF 0x1
+#define FUNC_LED_ON 0x30001
+#define KEYBOARD_LAMPS 0x100
+#define LOGOLAMP_POWERON 0x2000
+#define LOGOLAMP_ALWAYS 0x4000
+#endif
+
/* Hotkey details */
#define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */
#define KEY2_CODE 0x411
@@ -133,7 +155,6 @@ struct fujitsu_t {
static struct fujitsu_t *fujitsu;
static int use_alt_lcd_levels = -1;
-static int disable_brightness_keys = -1;
static int disable_brightness_adjust = -1;
/* Device used to access other hotkeys on the laptop */
@@ -145,8 +166,9 @@ struct fujitsu_hotkey_t {
struct platform_device *pf_device;
struct kfifo *fifo;
spinlock_t fifo_lock;
-
- unsigned int irb; /* info about the pressed buttons */
+ int rfkill_state;
+ int logolamp_registered;
+ int kblamps_registered;
};
static struct fujitsu_hotkey_t *fujitsu_hotkey;
@@ -154,12 +176,139 @@ static struct fujitsu_hotkey_t *fujitsu_hotkey;
static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
void *data);
+#ifdef CONFIG_LEDS_CLASS
+static enum led_brightness logolamp_get(struct led_classdev *cdev);
+static void logolamp_set(struct led_classdev *cdev,
+ enum led_brightness brightness);
+
+struct led_classdev logolamp_led = {
+ .name = "fujitsu::logolamp",
+ .brightness_get = logolamp_get,
+ .brightness_set = logolamp_set
+};
+
+static enum led_brightness kblamps_get(struct led_classdev *cdev);
+static void kblamps_set(struct led_classdev *cdev,
+ enum led_brightness brightness);
+
+struct led_classdev kblamps_led = {
+ .name = "fujitsu::kblamps",
+ .brightness_get = kblamps_get,
+ .brightness_set = kblamps_set
+};
+#endif
+
#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
static u32 dbg_level = 0x03;
#endif
static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data);
+/* Fujitsu ACPI interface function */
+
+static int call_fext_func(int cmd, int arg0, int arg1, int arg2)
+{
+ acpi_status status = AE_OK;
+ union acpi_object params[4] = {
+ { .type = ACPI_TYPE_INTEGER },
+ { .type = ACPI_TYPE_INTEGER },
+ { .type = ACPI_TYPE_INTEGER },
+ { .type = ACPI_TYPE_INTEGER }
+ };
+ struct acpi_object_list arg_list = { 4, &params[0] };
+ struct acpi_buffer output;
+ union acpi_object out_obj;
+ acpi_handle handle = NULL;
+
+ status = acpi_get_handle(fujitsu_hotkey->acpi_handle, "FUNC", &handle);
+ if (ACPI_FAILURE(status)) {
+ vdbg_printk(FUJLAPTOP_DBG_ERROR,
+ "FUNC interface is not present\n");
+ return -ENODEV;
+ }
+
+ params[0].integer.value = cmd;
+ params[1].integer.value = arg0;
+ params[2].integer.value = arg1;
+ params[3].integer.value = arg2;
+
+ output.length = sizeof(out_obj);
+ output.pointer = &out_obj;
+
+ status = acpi_evaluate_object(handle, NULL, &arg_list, &output);
+ if (ACPI_FAILURE(status)) {
+ vdbg_printk(FUJLAPTOP_DBG_WARN,
+ "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n",
+ cmd, arg0, arg1, arg2);
+ return -ENODEV;
+ }
+
+ if (out_obj.type != ACPI_TYPE_INTEGER) {
+ vdbg_printk(FUJLAPTOP_DBG_WARN,
+ "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) did not "
+ "return an integer\n",
+ cmd, arg0, arg1, arg2);
+ return -ENODEV;
+ }
+
+ vdbg_printk(FUJLAPTOP_DBG_TRACE,
+ "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
+ cmd, arg0, arg1, arg2, (int)out_obj.integer.value);
+ return out_obj.integer.value;
+}
+
+#ifdef CONFIG_LEDS_CLASS
+/* LED class callbacks */
+
+static void logolamp_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ if (brightness >= LED_FULL) {
+ call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
+ call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON);
+ } else if (brightness >= LED_HALF) {
+ call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
+ call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF);
+ } else {
+ call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF);
+ }
+}
+
+static void kblamps_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ if (brightness >= LED_FULL)
+ call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON);
+ else
+ call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF);
+}
+
+static enum led_brightness logolamp_get(struct led_classdev *cdev)
+{
+ enum led_brightness brightness = LED_OFF;
+ int poweron, always;
+
+ poweron = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
+ if (poweron == FUNC_LED_ON) {
+ brightness = LED_HALF;
+ always = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
+ if (always == FUNC_LED_ON)
+ brightness = LED_FULL;
+ }
+ return brightness;
+}
+
+static enum led_brightness kblamps_get(struct led_classdev *cdev)
+{
+ enum led_brightness brightness = LED_OFF;
+
+ if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
+ brightness = LED_FULL;
+
+ return brightness;
+}
+#endif
+
/* Hardware access for LCD brightness control */
static int set_lcd_level(int level)
@@ -263,44 +412,34 @@ static int get_max_brightness(void)
return fujitsu->max_brightness;
}
-static int get_lcd_level_alt(void)
-{
- unsigned long long state = 0;
- acpi_status status = AE_OK;
-
- vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLS\n");
-
- status =
- acpi_evaluate_integer(fujitsu->acpi_handle, "GBLS", NULL, &state);
- if (status < 0)
- return status;
-
- fujitsu->brightness_level = state & 0x0fffffff;
-
- if (state & 0x80000000)
- fujitsu->brightness_changed = 1;
- else
- fujitsu->brightness_changed = 0;
-
- return fujitsu->brightness_level;
-}
-
/* Backlight device stuff */
static int bl_get_brightness(struct backlight_device *b)
{
- if (use_alt_lcd_levels)
- return get_lcd_level_alt();
- else
- return get_lcd_level();
+ return get_lcd_level();
}
static int bl_update_status(struct backlight_device *b)
{
+ int ret;
+ if (b->props.power == 4)
+ ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3);
+ else
+ ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
+ if (ret != 0)
+ vdbg_printk(FUJLAPTOP_DBG_ERROR,
+ "Unable to adjust backlight power, error code %i\n",
+ ret);
+
if (use_alt_lcd_levels)
- return set_lcd_level_alt(b->props.brightness);
+ ret = set_lcd_level_alt(b->props.brightness);
else
- return set_lcd_level(b->props.brightness);
+ ret = set_lcd_level(b->props.brightness);
+ if (ret != 0)
+ vdbg_printk(FUJLAPTOP_DBG_ERROR,
+ "Unable to adjust LCD brightness, error code %i\n",
+ ret);
+ return ret;
}
static struct backlight_ops fujitsubl_ops = {
@@ -344,10 +483,7 @@ static ssize_t show_lcd_level(struct device *dev,
int ret;
- if (use_alt_lcd_levels)
- ret = get_lcd_level_alt();
- else
- ret = get_lcd_level();
+ ret = get_lcd_level();
if (ret < 0)
return ret;
@@ -372,52 +508,71 @@ static ssize_t store_lcd_level(struct device *dev,
if (ret < 0)
return ret;
- if (use_alt_lcd_levels)
- ret = get_lcd_level_alt();
- else
- ret = get_lcd_level();
+ ret = get_lcd_level();
if (ret < 0)
return ret;
return count;
}
-/* Hardware access for hotkey device */
-
-static int get_irb(void)
+static ssize_t
+ignore_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
- unsigned long long state = 0;
- acpi_status status = AE_OK;
-
- vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n");
-
- status =
- acpi_evaluate_integer(fujitsu_hotkey->acpi_handle, "GIRB", NULL,
- &state);
- if (status < 0)
- return status;
+ return count;
+}
- fujitsu_hotkey->irb = state;
+static ssize_t
+show_lid_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD)
+ return sprintf(buf, "unknown\n");
+ if (fujitsu_hotkey->rfkill_state & 0x100)
+ return sprintf(buf, "open\n");
+ else
+ return sprintf(buf, "closed\n");
+}
- return fujitsu_hotkey->irb;
+static ssize_t
+show_dock_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD)
+ return sprintf(buf, "unknown\n");
+ if (fujitsu_hotkey->rfkill_state & 0x200)
+ return sprintf(buf, "docked\n");
+ else
+ return sprintf(buf, "undocked\n");
}
static ssize_t
-ignore_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+show_radios_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- return count;
+ if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD)
+ return sprintf(buf, "unknown\n");
+ if (fujitsu_hotkey->rfkill_state & 0x20)
+ return sprintf(buf, "on\n");
+ else
+ return sprintf(buf, "killed\n");
}
static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store);
static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed,
ignore_store);
static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
+static DEVICE_ATTR(lid, 0444, show_lid_state, ignore_store);
+static DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store);
+static DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store);
static struct attribute *fujitsupf_attributes[] = {
&dev_attr_brightness_changed.attr,
&dev_attr_max_brightness.attr,
&dev_attr_lcd_level.attr,
+ &dev_attr_lid.attr,
+ &dev_attr_dock.attr,
+ &dev_attr_radios.attr,
NULL
};
@@ -435,24 +590,16 @@ static struct platform_driver fujitsupf_driver = {
static void dmi_check_cb_common(const struct dmi_system_id *id)
{
acpi_handle handle;
- int have_blnf;
printk(KERN_INFO "fujitsu-laptop: Identified laptop model '%s'.\n",
id->ident);
- have_blnf = ACPI_SUCCESS
- (acpi_get_handle(NULL, "\\_SB.PCI0.GFX0.LCD.BLNF", &handle));
if (use_alt_lcd_levels == -1) {
- vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detecting usealt\n");
- use_alt_lcd_levels = 1;
- }
- if (disable_brightness_keys == -1) {
- vdbg_printk(FUJLAPTOP_DBG_TRACE,
- "auto-detecting disable_keys\n");
- disable_brightness_keys = have_blnf ? 1 : 0;
- }
- if (disable_brightness_adjust == -1) {
- vdbg_printk(FUJLAPTOP_DBG_TRACE,
- "auto-detecting disable_adjust\n");
- disable_brightness_adjust = have_blnf ? 0 : 1;
+ if (ACPI_SUCCESS(acpi_get_handle(NULL,
+ "\\_SB.PCI0.LPCB.FJEX.SBL2", &handle)))
+ use_alt_lcd_levels = 1;
+ else
+ use_alt_lcd_levels = 0;
+ vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as "
+ "%i\n", use_alt_lcd_levels);
}
}
@@ -581,19 +728,14 @@ static int acpi_fujitsu_add(struct acpi_device *device)
/* do config (detect defaults) */
use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
- disable_brightness_keys = disable_brightness_keys == 1 ? 1 : 0;
disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0;
vdbg_printk(FUJLAPTOP_DBG_INFO,
- "config: [alt interface: %d], [key disable: %d], [adjust disable: %d]\n",
- use_alt_lcd_levels, disable_brightness_keys,
- disable_brightness_adjust);
+ "config: [alt interface: %d], [adjust disable: %d]\n",
+ use_alt_lcd_levels, disable_brightness_adjust);
if (get_max_brightness() <= 0)
fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS;
- if (use_alt_lcd_levels)
- get_lcd_level_alt();
- else
- get_lcd_level();
+ get_lcd_level();
return result;
@@ -644,43 +786,23 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
case ACPI_FUJITSU_NOTIFY_CODE1:
keycode = 0;
oldb = fujitsu->brightness_level;
- get_lcd_level(); /* the alt version always yields changed */
+ get_lcd_level();
newb = fujitsu->brightness_level;
vdbg_printk(FUJLAPTOP_DBG_TRACE,
"brightness button event [%i -> %i (%i)]\n",
oldb, newb, fujitsu->brightness_changed);
- if (oldb == newb && fujitsu->brightness_changed) {
- keycode = 0;
- if (disable_brightness_keys != 1) {
- if (oldb == 0) {
- acpi_bus_generate_proc_event
- (fujitsu->dev,
- ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS,
- 0);
- keycode = KEY_BRIGHTNESSDOWN;
- } else if (oldb ==
- (fujitsu->max_brightness) - 1) {
- acpi_bus_generate_proc_event
- (fujitsu->dev,
- ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS,
- 0);
- keycode = KEY_BRIGHTNESSUP;
- }
- }
- } else if (oldb < newb) {
+ if (oldb < newb) {
if (disable_brightness_adjust != 1) {
if (use_alt_lcd_levels)
set_lcd_level_alt(newb);
else
set_lcd_level(newb);
}
- if (disable_brightness_keys != 1) {
- acpi_bus_generate_proc_event(fujitsu->dev,
- ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0);
- keycode = KEY_BRIGHTNESSUP;
- }
+ acpi_bus_generate_proc_event(fujitsu->dev,
+ ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0);
+ keycode = KEY_BRIGHTNESSUP;
} else if (oldb > newb) {
if (disable_brightness_adjust != 1) {
if (use_alt_lcd_levels)
@@ -688,13 +810,9 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data)
else
set_lcd_level(newb);
}
- if (disable_brightness_keys != 1) {
- acpi_bus_generate_proc_event(fujitsu->dev,
- ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0);
- keycode = KEY_BRIGHTNESSDOWN;
- }
- } else {
- keycode = KEY_UNKNOWN;
+ acpi_bus_generate_proc_event(fujitsu->dev,
+ ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0);
+ keycode = KEY_BRIGHTNESSDOWN;
}
break;
default:
@@ -771,7 +889,8 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
input->id.bustype = BUS_HOST;
input->id.product = 0x06;
input->dev.parent = &device->dev;
- input->evbit[0] = BIT(EV_KEY);
+
+ set_bit(EV_KEY, input->evbit);
set_bit(fujitsu->keycode1, input->keybit);
set_bit(fujitsu->keycode2, input->keybit);
set_bit(fujitsu->keycode3, input->keybit);
@@ -803,10 +922,44 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
printk(KERN_ERR "_INI Method failed\n");
}
- i = 0; /* Discard hotkey ringbuffer */
- while (get_irb() != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ;
+ i = 0;
+ while (call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0
+ && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE)
+ ; /* No action, result is discarded */
vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i);
+ fujitsu_hotkey->rfkill_state =
+ call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
+
+ /* Suspect this is a keymap of the application panel, print it */
+ printk(KERN_INFO "fujitsu-laptop: BTNI: [0x%x]\n",
+ call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0));
+
+ #ifdef CONFIG_LEDS_CLASS
+ if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
+ result = led_classdev_register(&fujitsu->pf_device->dev,
+ &logolamp_led);
+ if (result == 0) {
+ fujitsu_hotkey->logolamp_registered = 1;
+ } else {
+ printk(KERN_ERR "fujitsu-laptop: Could not register "
+ "LED handler for logo lamp, error %i\n", result);
+ }
+ }
+
+ if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
+ (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
+ result = led_classdev_register(&fujitsu->pf_device->dev,
+ &kblamps_led);
+ if (result == 0) {
+ fujitsu_hotkey->kblamps_registered = 1;
+ } else {
+ printk(KERN_ERR "fujitsu-laptop: Could not register "
+ "LED handler for keyboard lamps, error %i\n", result);
+ }
+ }
+ #endif
+
return result;
end:
@@ -852,16 +1005,15 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
input = fujitsu_hotkey->input;
- vdbg_printk(FUJLAPTOP_DBG_TRACE, "Hotkey event\n");
+ fujitsu_hotkey->rfkill_state =
+ call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
switch (event) {
case ACPI_FUJITSU_NOTIFY_CODE1:
i = 0;
- while ((irb = get_irb()) != 0
- && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
- vdbg_printk(FUJLAPTOP_DBG_TRACE, "GIRB result [%x]\n",
- irb);
-
+ while ((irb =
+ call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0
+ && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
switch (irb & 0x4ff) {
case KEY1_CODE:
keycode = fujitsu->keycode1;
@@ -1035,6 +1187,15 @@ static int __init fujitsu_init(void)
goto fail_hotkey1;
}
+ /* Sync backlight power status (needs FUJ02E3 device, hence deferred) */
+
+ if (!acpi_video_backlight_support()) {
+ if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3)
+ fujitsu->bl_device->props.power = 4;
+ else
+ fujitsu->bl_device->props.power = 0;
+ }
+
printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION
" successfully loaded.\n");
@@ -1074,6 +1235,14 @@ fail_acpi:
static void __exit fujitsu_cleanup(void)
{
+ #ifdef CONFIG_LEDS_CLASS
+ if (fujitsu_hotkey->logolamp_registered != 0)
+ led_classdev_unregister(&logolamp_led);
+
+ if (fujitsu_hotkey->kblamps_registered != 0)
+ led_classdev_unregister(&kblamps_led);
+ #endif
+
sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
&fujitsupf_attribute_group);
platform_device_unregister(fujitsu->pf_device);
@@ -1098,9 +1267,6 @@ module_exit(fujitsu_cleanup);
module_param(use_alt_lcd_levels, uint, 0644);
MODULE_PARM_DESC(use_alt_lcd_levels,
"Use alternative interface for lcd_levels (needed for Lifebook s6410).");
-module_param(disable_brightness_keys, uint, 0644);
-MODULE_PARM_DESC(disable_brightness_keys,
- "Disable brightness keys (eg. if they are already handled by the generic ACPI_VIDEO device).");
module_param(disable_brightness_adjust, uint, 0644);
MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment .");
#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
@@ -1108,12 +1274,13 @@ module_param_named(debug, dbg_level, uint, 0644);
MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
#endif
-MODULE_AUTHOR("Jonathan Woithe, Peter Gruber");
+MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon");
MODULE_DESCRIPTION("Fujitsu laptop extras support");
MODULE_VERSION(FUJITSU_DRIVER_VERSION);
MODULE_LICENSE("GPL");
MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
+MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*");
MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
static struct pnp_device_id pnp_ids[] = {
diff --git a/drivers/misc/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 4b7c24c519c3..7c789f0a94d7 100644
--- a/drivers/misc/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -428,7 +428,9 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
wifi_rfkill->state = hp_wmi_wifi_state();
wifi_rfkill->toggle_radio = hp_wmi_wifi_set;
wifi_rfkill->user_claim_unsupported = 1;
- rfkill_register(wifi_rfkill);
+ err = rfkill_register(wifi_rfkill);
+ if (err)
+ goto add_sysfs_error;
}
if (wireless & 0x2) {
@@ -438,7 +440,8 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
bluetooth_rfkill->state = hp_wmi_bluetooth_state();
bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set;
bluetooth_rfkill->user_claim_unsupported = 1;
- rfkill_register(bluetooth_rfkill);
+ err = rfkill_register(bluetooth_rfkill);
+ goto register_bluetooth_error;
}
if (wireless & 0x4) {
@@ -447,10 +450,16 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
wwan_rfkill->state = hp_wmi_wwan_state();
wwan_rfkill->toggle_radio = hp_wmi_wwan_set;
wwan_rfkill->user_claim_unsupported = 1;
- rfkill_register(wwan_rfkill);
+ err = rfkill_register(wwan_rfkill);
+ if (err)
+ goto register_wwan_err;
}
return 0;
+register_wwan_err:
+ rfkill_unregister(bluetooth_rfkill);
+register_bluetooth_error:
+ rfkill_unregister(wifi_rfkill);
add_sysfs_error:
cleanup_sysfs(device);
return err;
diff --git a/drivers/misc/intel_menlow.c b/drivers/platform/x86/intel_menlow.c
index 27b7662955bb..27b7662955bb 100644
--- a/drivers/misc/intel_menlow.c
+++ b/drivers/platform/x86/intel_menlow.c
diff --git a/drivers/misc/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 759763d18e4c..759763d18e4c 100644
--- a/drivers/misc/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
diff --git a/drivers/misc/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 4a1bc64485d5..f30db367c82e 100644
--- a/drivers/misc/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -241,8 +241,6 @@ static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val)
};
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_pcc_write_sset");
-
status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET,
&params, NULL);
@@ -254,8 +252,6 @@ static inline int acpi_pcc_get_sqty(struct acpi_device *device)
unsigned long long s;
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_pcc_get_sqty");
-
status = acpi_evaluate_integer(device->handle, METHOD_HKEY_SQTY,
NULL, &s);
if (ACPI_SUCCESS(status))
@@ -274,8 +270,6 @@ static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf)
union acpi_object *hkey = NULL;
int i;
- ACPI_FUNCTION_TRACE("acpi_pcc_retrieve_biosdata");
-
status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SINF, 0,
&buffer);
if (ACPI_FAILURE(status)) {
@@ -501,8 +495,6 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
int key_code, hkey_num;
unsigned long long result;
- ACPI_FUNCTION_TRACE("acpi_pcc_generate_keyinput");
-
rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
NULL, &result);
if (!ACPI_SUCCESS(rc)) {
@@ -538,8 +530,6 @@ static void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data)
{
struct pcc_acpi *pcc = (struct pcc_acpi *) data;
- ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_notify");
-
switch (event) {
case HKEY_NOTIFY:
acpi_pcc_generate_keyinput(pcc);
@@ -554,8 +544,6 @@ static int acpi_pcc_init_input(struct pcc_acpi *pcc)
{
int i, rc;
- ACPI_FUNCTION_TRACE("acpi_pcc_init_input");
-
pcc->input_dev = input_allocate_device();
if (!pcc->input_dev) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
@@ -597,8 +585,6 @@ static int acpi_pcc_hotkey_resume(struct acpi_device *device)
struct pcc_acpi *pcc = acpi_driver_data(device);
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_resume");
-
if (device == NULL || pcc == NULL)
return -EINVAL;
@@ -616,8 +602,6 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
struct pcc_acpi *pcc;
int num_sifr, result;
- ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_add");
-
if (!device)
return -EINVAL;
@@ -714,8 +698,6 @@ static int __init acpi_pcc_init(void)
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_pcc_init");
-
if (acpi_disabled)
return -ENODEV;
@@ -733,8 +715,6 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
{
struct pcc_acpi *pcc = acpi_driver_data(device);
- ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_remove");
-
if (!device || !pcc)
return -EINVAL;
@@ -757,8 +737,6 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
static void __exit acpi_pcc_exit(void)
{
- ACPI_FUNCTION_TRACE("acpi_pcc_exit");
-
acpi_bus_unregister_driver(&acpi_pcc_driver);
}
diff --git a/drivers/misc/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 571b211608d1..537959d07148 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -935,14 +935,17 @@ static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
void *context, void **return_value)
{
- struct acpi_namespace_node *node;
- union acpi_operand_object *operand;
+ struct acpi_device_info *info;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
- node = (struct acpi_namespace_node *)handle;
- operand = (union acpi_operand_object *)node->object;
+ if (ACPI_SUCCESS(acpi_get_object_info(handle, &buffer))) {
+ info = buffer.pointer;
- printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
- (u32) operand->method.param_count);
+ printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n",
+ (char *)&info->name, info->param_count);
+
+ kfree(buffer.pointer);
+ }
return AE_OK;
}
diff --git a/drivers/misc/tc1100-wmi.c b/drivers/platform/x86/tc1100-wmi.c
index f25e4c974dcf..b4a4aa9ee482 100644
--- a/drivers/misc/tc1100-wmi.c
+++ b/drivers/platform/x86/tc1100-wmi.c
@@ -30,7 +30,6 @@
#include <linux/init.h>
#include <linux/types.h>
#include <acpi/acpi.h>
-#include <acpi/actypes.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/platform_device.h>
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 899766e16fa8..bcbc05107ba8 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -21,7 +21,7 @@
* 02110-1301, USA.
*/
-#define TPACPI_VERSION "0.21"
+#define TPACPI_VERSION "0.22"
#define TPACPI_SYSFS_VERSION 0x020200
/*
@@ -76,7 +76,6 @@
#include <linux/workqueue.h>
#include <acpi/acpi_drivers.h>
-#include <acpi/acnamesp.h>
#include <linux/pci_ids.h>
@@ -123,6 +122,27 @@ enum {
#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */
#define TPACPI_HKEY_INPUT_VERSION 0x4101
+/* ACPI \WGSV commands */
+enum {
+ TP_ACPI_WGSV_GET_STATE = 0x01, /* Get state information */
+ TP_ACPI_WGSV_PWR_ON_ON_RESUME = 0x02, /* Resume WWAN powered on */
+ TP_ACPI_WGSV_PWR_OFF_ON_RESUME = 0x03, /* Resume WWAN powered off */
+ TP_ACPI_WGSV_SAVE_STATE = 0x04, /* Save state for S4/S5 */
+};
+
+/* TP_ACPI_WGSV_GET_STATE bits */
+enum {
+ TP_ACPI_WGSV_STATE_WWANEXIST = 0x0001, /* WWAN hw available */
+ TP_ACPI_WGSV_STATE_WWANPWR = 0x0002, /* WWAN radio enabled */
+ TP_ACPI_WGSV_STATE_WWANPWRRES = 0x0004, /* WWAN state at resume */
+ TP_ACPI_WGSV_STATE_WWANBIOSOFF = 0x0008, /* WWAN disabled in BIOS */
+ TP_ACPI_WGSV_STATE_BLTHEXIST = 0x0001, /* BLTH hw available */
+ TP_ACPI_WGSV_STATE_BLTHPWR = 0x0002, /* BLTH radio enabled */
+ TP_ACPI_WGSV_STATE_BLTHPWRRES = 0x0004, /* BLTH state at resume */
+ TP_ACPI_WGSV_STATE_BLTHBIOSOFF = 0x0008, /* BLTH disabled in BIOS */
+ TP_ACPI_WGSV_STATE_UWBEXIST = 0x0010, /* UWB hw available */
+ TP_ACPI_WGSV_STATE_UWBPWR = 0x0020, /* UWB radio enabled */
+};
/****************************************************************************
* Main driver
@@ -149,14 +169,17 @@ enum {
enum {
TPACPI_RFK_BLUETOOTH_SW_ID = 0,
TPACPI_RFK_WWAN_SW_ID,
+ TPACPI_RFK_UWB_SW_ID,
};
/* Debugging */
#define TPACPI_LOG TPACPI_FILE ": "
-#define TPACPI_ERR KERN_ERR TPACPI_LOG
-#define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG
-#define TPACPI_INFO KERN_INFO TPACPI_LOG
-#define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG
+#define TPACPI_ALERT KERN_ALERT TPACPI_LOG
+#define TPACPI_CRIT KERN_CRIT TPACPI_LOG
+#define TPACPI_ERR KERN_ERR TPACPI_LOG
+#define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG
+#define TPACPI_INFO KERN_INFO TPACPI_LOG
+#define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG
#define TPACPI_DBG_ALL 0xffff
#define TPACPI_DBG_INIT 0x0001
@@ -202,6 +225,7 @@ struct ibm_struct {
void (*exit) (void);
void (*resume) (void);
void (*suspend) (pm_message_t state);
+ void (*shutdown) (void);
struct list_head all_drivers;
@@ -240,6 +264,7 @@ static struct {
u32 bright_16levels:1;
u32 bright_acpimode:1;
u32 wan:1;
+ u32 uwb:1;
u32 fan_ctrl_status_undef:1;
u32 input_device_registered:1;
u32 platform_drv_registered:1;
@@ -289,6 +314,18 @@ struct tpacpi_led_classdev {
unsigned int led;
};
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+static int dbg_wlswemul;
+static int tpacpi_wlsw_emulstate;
+static int dbg_bluetoothemul;
+static int tpacpi_bluetooth_emulstate;
+static int dbg_wwanemul;
+static int tpacpi_wwan_emulstate;
+static int dbg_uwbemul;
+static int tpacpi_uwb_emulstate;
+#endif
+
+
/****************************************************************************
****************************************************************************
*
@@ -729,6 +766,18 @@ static int tpacpi_resume_handler(struct platform_device *pdev)
return 0;
}
+static void tpacpi_shutdown_handler(struct platform_device *pdev)
+{
+ struct ibm_struct *ibm, *itmp;
+
+ list_for_each_entry_safe(ibm, itmp,
+ &tpacpi_all_drivers,
+ all_drivers) {
+ if (ibm->shutdown)
+ (ibm->shutdown)();
+ }
+}
+
static struct platform_driver tpacpi_pdriver = {
.driver = {
.name = TPACPI_DRVR_NAME,
@@ -736,6 +785,7 @@ static struct platform_driver tpacpi_pdriver = {
},
.suspend = tpacpi_suspend_handler,
.resume = tpacpi_resume_handler,
+ .shutdown = tpacpi_shutdown_handler,
};
static struct platform_driver tpacpi_hwmon_pdriver = {
@@ -923,11 +973,27 @@ static int __init tpacpi_new_rfkill(const unsigned int id,
struct rfkill **rfk,
const enum rfkill_type rfktype,
const char *name,
+ const bool set_default,
int (*toggle_radio)(void *, enum rfkill_state),
int (*get_state)(void *, enum rfkill_state *))
{
int res;
- enum rfkill_state initial_state;
+ enum rfkill_state initial_state = RFKILL_STATE_SOFT_BLOCKED;
+
+ res = get_state(NULL, &initial_state);
+ if (res < 0) {
+ printk(TPACPI_ERR
+ "failed to read initial state for %s, error %d; "
+ "will turn radio off\n", name, res);
+ } else if (set_default) {
+ /* try to set the initial state as the default for the rfkill
+ * type, since we ask the firmware to preserve it across S5 in
+ * NVRAM */
+ rfkill_set_default(rfktype,
+ (initial_state == RFKILL_STATE_UNBLOCKED) ?
+ RFKILL_STATE_UNBLOCKED :
+ RFKILL_STATE_SOFT_BLOCKED);
+ }
*rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype);
if (!*rfk) {
@@ -939,9 +1005,7 @@ static int __init tpacpi_new_rfkill(const unsigned int id,
(*rfk)->name = name;
(*rfk)->get_state = get_state;
(*rfk)->toggle_radio = toggle_radio;
-
- if (!get_state(NULL, &initial_state))
- (*rfk)->state = initial_state;
+ (*rfk)->state = initial_state;
res = rfkill_register(*rfk);
if (res < 0) {
@@ -1007,6 +1071,119 @@ static DRIVER_ATTR(version, S_IRUGO,
/* --------------------------------------------------------------------- */
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+
+static void tpacpi_send_radiosw_update(void);
+
+/* wlsw_emulstate ------------------------------------------------------ */
+static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_wlsw_emulstate);
+}
+
+static ssize_t tpacpi_driver_wlsw_emulstate_store(struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+
+ if (parse_strtoul(buf, 1, &t))
+ return -EINVAL;
+
+ if (tpacpi_wlsw_emulstate != t) {
+ tpacpi_wlsw_emulstate = !!t;
+ tpacpi_send_radiosw_update();
+ } else
+ tpacpi_wlsw_emulstate = !!t;
+
+ return count;
+}
+
+static DRIVER_ATTR(wlsw_emulstate, S_IWUSR | S_IRUGO,
+ tpacpi_driver_wlsw_emulstate_show,
+ tpacpi_driver_wlsw_emulstate_store);
+
+/* bluetooth_emulstate ------------------------------------------------- */
+static ssize_t tpacpi_driver_bluetooth_emulstate_show(
+ struct device_driver *drv,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_bluetooth_emulstate);
+}
+
+static ssize_t tpacpi_driver_bluetooth_emulstate_store(
+ struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+
+ if (parse_strtoul(buf, 1, &t))
+ return -EINVAL;
+
+ tpacpi_bluetooth_emulstate = !!t;
+
+ return count;
+}
+
+static DRIVER_ATTR(bluetooth_emulstate, S_IWUSR | S_IRUGO,
+ tpacpi_driver_bluetooth_emulstate_show,
+ tpacpi_driver_bluetooth_emulstate_store);
+
+/* wwan_emulstate ------------------------------------------------- */
+static ssize_t tpacpi_driver_wwan_emulstate_show(
+ struct device_driver *drv,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_wwan_emulstate);
+}
+
+static ssize_t tpacpi_driver_wwan_emulstate_store(
+ struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+
+ if (parse_strtoul(buf, 1, &t))
+ return -EINVAL;
+
+ tpacpi_wwan_emulstate = !!t;
+
+ return count;
+}
+
+static DRIVER_ATTR(wwan_emulstate, S_IWUSR | S_IRUGO,
+ tpacpi_driver_wwan_emulstate_show,
+ tpacpi_driver_wwan_emulstate_store);
+
+/* uwb_emulstate ------------------------------------------------- */
+static ssize_t tpacpi_driver_uwb_emulstate_show(
+ struct device_driver *drv,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_uwb_emulstate);
+}
+
+static ssize_t tpacpi_driver_uwb_emulstate_store(
+ struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+
+ if (parse_strtoul(buf, 1, &t))
+ return -EINVAL;
+
+ tpacpi_uwb_emulstate = !!t;
+
+ return count;
+}
+
+static DRIVER_ATTR(uwb_emulstate, S_IWUSR | S_IRUGO,
+ tpacpi_driver_uwb_emulstate_show,
+ tpacpi_driver_uwb_emulstate_store);
+#endif
+
+/* --------------------------------------------------------------------- */
+
static struct driver_attribute *tpacpi_driver_attributes[] = {
&driver_attr_debug_level, &driver_attr_version,
&driver_attr_interface_version,
@@ -1023,6 +1200,17 @@ static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
i++;
}
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+ if (!res && dbg_wlswemul)
+ res = driver_create_file(drv, &driver_attr_wlsw_emulstate);
+ if (!res && dbg_bluetoothemul)
+ res = driver_create_file(drv, &driver_attr_bluetooth_emulstate);
+ if (!res && dbg_wwanemul)
+ res = driver_create_file(drv, &driver_attr_wwan_emulstate);
+ if (!res && dbg_uwbemul)
+ res = driver_create_file(drv, &driver_attr_uwb_emulstate);
+#endif
+
return res;
}
@@ -1032,6 +1220,13 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv)
for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
driver_remove_file(drv, tpacpi_driver_attributes[i]);
+
+#ifdef THINKPAD_ACPI_DEBUGFACILITIES
+ driver_remove_file(drv, &driver_attr_wlsw_emulstate);
+ driver_remove_file(drv, &driver_attr_bluetooth_emulstate);
+ driver_remove_file(drv, &driver_attr_wwan_emulstate);
+ driver_remove_file(drv, &driver_attr_uwb_emulstate);
+#endif
}
/****************************************************************************
@@ -1217,6 +1412,12 @@ static struct attribute_set *hotkey_dev_attributes;
static int hotkey_get_wlsw(int *status)
{
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+ if (dbg_wlswemul) {
+ *status = !!tpacpi_wlsw_emulstate;
+ return 0;
+ }
+#endif
if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
return -EIO;
return 0;
@@ -1679,7 +1880,7 @@ static ssize_t hotkey_mask_show(struct device *dev,
{
int res;
- if (mutex_lock_interruptible(&hotkey_mutex))
+ if (mutex_lock_killable(&hotkey_mutex))
return -ERESTARTSYS;
res = hotkey_mask_get();
mutex_unlock(&hotkey_mutex);
@@ -1698,7 +1899,7 @@ static ssize_t hotkey_mask_store(struct device *dev,
if (parse_strtoul(buf, 0xffffffffUL, &t))
return -EINVAL;
- if (mutex_lock_interruptible(&hotkey_mutex))
+ if (mutex_lock_killable(&hotkey_mutex))
return -ERESTARTSYS;
res = hotkey_mask_set(t);
@@ -1784,7 +1985,7 @@ static ssize_t hotkey_source_mask_store(struct device *dev,
((t & ~TPACPI_HKEY_NVRAM_KNOWN_MASK) != 0))
return -EINVAL;
- if (mutex_lock_interruptible(&hotkey_mutex))
+ if (mutex_lock_killable(&hotkey_mutex))
return -ERESTARTSYS;
HOTKEY_CONFIG_CRITICAL_START
@@ -1819,7 +2020,7 @@ static ssize_t hotkey_poll_freq_store(struct device *dev,
if (parse_strtoul(buf, 25, &t))
return -EINVAL;
- if (mutex_lock_interruptible(&hotkey_mutex))
+ if (mutex_lock_killable(&hotkey_mutex))
return -ERESTARTSYS;
hotkey_poll_freq = t;
@@ -1959,6 +2160,7 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {
static void bluetooth_update_rfk(void);
static void wan_update_rfk(void);
+static void uwb_update_rfk(void);
static void tpacpi_send_radiosw_update(void)
{
int wlsw;
@@ -1968,6 +2170,8 @@ static void tpacpi_send_radiosw_update(void)
bluetooth_update_rfk();
if (tp_features.wan)
wan_update_rfk();
+ if (tp_features.uwb)
+ uwb_update_rfk();
if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
mutex_lock(&tpacpi_inputdev_send_mutex);
@@ -2223,6 +2427,13 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
hotkey_source_mask, hotkey_poll_freq);
#endif
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+ if (dbg_wlswemul) {
+ tp_features.hotkey_wlsw = 1;
+ printk(TPACPI_INFO
+ "radio switch emulation enabled\n");
+ } else
+#endif
/* Not all thinkpads have a hardware radio switch */
if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
tp_features.hotkey_wlsw = 1;
@@ -2362,13 +2573,154 @@ err_exit:
return (res < 0)? res : 1;
}
+static bool hotkey_notify_hotkey(const u32 hkey,
+ bool *send_acpi_ev,
+ bool *ignore_acpi_ev)
+{
+ /* 0x1000-0x1FFF: key presses */
+ unsigned int scancode = hkey & 0xfff;
+ *send_acpi_ev = true;
+ *ignore_acpi_ev = false;
+
+ if (scancode > 0 && scancode < 0x21) {
+ scancode--;
+ if (!(hotkey_source_mask & (1 << scancode))) {
+ tpacpi_input_send_key(scancode);
+ *send_acpi_ev = false;
+ } else {
+ *ignore_acpi_ev = true;
+ }
+ return true;
+ }
+ return false;
+}
+
+static bool hotkey_notify_wakeup(const u32 hkey,
+ bool *send_acpi_ev,
+ bool *ignore_acpi_ev)
+{
+ /* 0x2000-0x2FFF: Wakeup reason */
+ *send_acpi_ev = true;
+ *ignore_acpi_ev = false;
+
+ switch (hkey) {
+ case 0x2304: /* suspend, undock */
+ case 0x2404: /* hibernation, undock */
+ hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK;
+ *ignore_acpi_ev = true;
+ break;
+
+ case 0x2305: /* suspend, bay eject */
+ case 0x2405: /* hibernation, bay eject */
+ hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ;
+ *ignore_acpi_ev = true;
+ break;
+
+ case 0x2313: /* Battery on critical low level (S3) */
+ case 0x2413: /* Battery on critical low level (S4) */
+ printk(TPACPI_ALERT
+ "EMERGENCY WAKEUP: battery almost empty\n");
+ /* how to auto-heal: */
+ /* 2313: woke up from S3, go to S4/S5 */
+ /* 2413: woke up from S4, go to S5 */
+ break;
+
+ default:
+ return false;
+ }
+
+ if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) {
+ printk(TPACPI_INFO
+ "woke up due to a hot-unplug "
+ "request...\n");
+ hotkey_wakeup_reason_notify_change();
+ }
+ return true;
+}
+
+static bool hotkey_notify_usrevent(const u32 hkey,
+ bool *send_acpi_ev,
+ bool *ignore_acpi_ev)
+{
+ /* 0x5000-0x5FFF: human interface helpers */
+ *send_acpi_ev = true;
+ *ignore_acpi_ev = false;
+
+ switch (hkey) {
+ case 0x5010: /* Lenovo new BIOS: brightness changed */
+ case 0x500b: /* X61t: tablet pen inserted into bay */
+ case 0x500c: /* X61t: tablet pen removed from bay */
+ return true;
+
+ case 0x5009: /* X41t-X61t: swivel up (tablet mode) */
+ case 0x500a: /* X41t-X61t: swivel down (normal mode) */
+ tpacpi_input_send_tabletsw();
+ hotkey_tablet_mode_notify_change();
+ *send_acpi_ev = false;
+ return true;
+
+ case 0x5001:
+ case 0x5002:
+ /* LID switch events. Do not propagate */
+ *ignore_acpi_ev = true;
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool hotkey_notify_thermal(const u32 hkey,
+ bool *send_acpi_ev,
+ bool *ignore_acpi_ev)
+{
+ /* 0x6000-0x6FFF: thermal alarms */
+ *send_acpi_ev = true;
+ *ignore_acpi_ev = false;
+
+ switch (hkey) {
+ case 0x6011:
+ printk(TPACPI_CRIT
+ "THERMAL ALARM: battery is too hot!\n");
+ /* recommended action: warn user through gui */
+ return true;
+ case 0x6012:
+ printk(TPACPI_ALERT
+ "THERMAL EMERGENCY: battery is extremely hot!\n");
+ /* recommended action: immediate sleep/hibernate */
+ return true;
+ case 0x6021:
+ printk(TPACPI_CRIT
+ "THERMAL ALARM: "
+ "a sensor reports something is too hot!\n");
+ /* recommended action: warn user through gui, that */
+ /* some internal component is too hot */
+ return true;
+ case 0x6022:
+ printk(TPACPI_ALERT
+ "THERMAL EMERGENCY: "
+ "a sensor reports something is extremely hot!\n");
+ /* recommended action: immediate sleep/hibernate */
+ return true;
+ case 0x6030:
+ printk(TPACPI_INFO
+ "EC reports that Thermal Table has changed\n");
+ /* recommended action: do nothing, we don't have
+ * Lenovo ATM information */
+ return true;
+ default:
+ printk(TPACPI_ALERT
+ "THERMAL ALERT: unknown thermal alarm received\n");
+ return false;
+ }
+}
+
static void hotkey_notify(struct ibm_struct *ibm, u32 event)
{
u32 hkey;
- unsigned int scancode;
- int send_acpi_ev;
- int ignore_acpi_ev;
- int unk_ev;
+ bool send_acpi_ev;
+ bool ignore_acpi_ev;
+ bool known_ev;
if (event != 0x80) {
printk(TPACPI_ERR
@@ -2376,7 +2728,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
/* forward it to userspace, maybe it knows how to handle it */
acpi_bus_generate_netlink_event(
ibm->acpi->device->pnp.device_class,
- ibm->acpi->device->dev.bus_id,
+ dev_name(&ibm->acpi->device->dev),
event, 0);
return;
}
@@ -2392,107 +2744,72 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
return;
}
- send_acpi_ev = 1;
- ignore_acpi_ev = 0;
- unk_ev = 0;
+ send_acpi_ev = true;
+ ignore_acpi_ev = false;
switch (hkey >> 12) {
case 1:
/* 0x1000-0x1FFF: key presses */
- scancode = hkey & 0xfff;
- if (scancode > 0 && scancode < 0x21) {
- scancode--;
- if (!(hotkey_source_mask & (1 << scancode))) {
- tpacpi_input_send_key(scancode);
- send_acpi_ev = 0;
- } else {
- ignore_acpi_ev = 1;
- }
- } else {
- unk_ev = 1;
- }
+ known_ev = hotkey_notify_hotkey(hkey, &send_acpi_ev,
+ &ignore_acpi_ev);
break;
case 2:
- /* Wakeup reason */
- switch (hkey) {
- case 0x2304: /* suspend, undock */
- case 0x2404: /* hibernation, undock */
- hotkey_wakeup_reason = TP_ACPI_WAKEUP_UNDOCK;
- ignore_acpi_ev = 1;
- break;
- case 0x2305: /* suspend, bay eject */
- case 0x2405: /* hibernation, bay eject */
- hotkey_wakeup_reason = TP_ACPI_WAKEUP_BAYEJ;
- ignore_acpi_ev = 1;
- break;
- default:
- unk_ev = 1;
- }
- if (hotkey_wakeup_reason != TP_ACPI_WAKEUP_NONE) {
- printk(TPACPI_INFO
- "woke up due to a hot-unplug "
- "request...\n");
- hotkey_wakeup_reason_notify_change();
- }
+ /* 0x2000-0x2FFF: Wakeup reason */
+ known_ev = hotkey_notify_wakeup(hkey, &send_acpi_ev,
+ &ignore_acpi_ev);
break;
case 3:
- /* bay-related wakeups */
+ /* 0x3000-0x3FFF: bay-related wakeups */
if (hkey == 0x3003) {
hotkey_autosleep_ack = 1;
printk(TPACPI_INFO
"bay ejected\n");
hotkey_wakeup_hotunplug_complete_notify_change();
+ known_ev = true;
} else {
- unk_ev = 1;
+ known_ev = false;
}
break;
case 4:
- /* dock-related wakeups */
+ /* 0x4000-0x4FFF: dock-related wakeups */
if (hkey == 0x4003) {
hotkey_autosleep_ack = 1;
printk(TPACPI_INFO
"undocked\n");
hotkey_wakeup_hotunplug_complete_notify_change();
+ known_ev = true;
} else {
- unk_ev = 1;
+ known_ev = false;
}
break;
case 5:
/* 0x5000-0x5FFF: human interface helpers */
- switch (hkey) {
- case 0x5010: /* Lenovo new BIOS: brightness changed */
- case 0x500b: /* X61t: tablet pen inserted into bay */
- case 0x500c: /* X61t: tablet pen removed from bay */
- break;
- case 0x5009: /* X41t-X61t: swivel up (tablet mode) */
- case 0x500a: /* X41t-X61t: swivel down (normal mode) */
- tpacpi_input_send_tabletsw();
- hotkey_tablet_mode_notify_change();
- send_acpi_ev = 0;
- break;
- case 0x5001:
- case 0x5002:
- /* LID switch events. Do not propagate */
- ignore_acpi_ev = 1;
- break;
- default:
- unk_ev = 1;
- }
+ known_ev = hotkey_notify_usrevent(hkey, &send_acpi_ev,
+ &ignore_acpi_ev);
+ break;
+ case 6:
+ /* 0x6000-0x6FFF: thermal alarms */
+ known_ev = hotkey_notify_thermal(hkey, &send_acpi_ev,
+ &ignore_acpi_ev);
break;
case 7:
/* 0x7000-0x7FFF: misc */
if (tp_features.hotkey_wlsw && hkey == 0x7000) {
tpacpi_send_radiosw_update();
send_acpi_ev = 0;
+ known_ev = true;
break;
}
/* fallthrough to default */
default:
- unk_ev = 1;
+ known_ev = false;
}
- if (unk_ev) {
+ if (!known_ev) {
printk(TPACPI_NOTICE
"unhandled HKEY event 0x%04x\n", hkey);
+ printk(TPACPI_NOTICE
+ "please report the conditions when this "
+ "event happened to %s\n", TPACPI_MAIL);
}
/* Legacy events */
@@ -2506,7 +2823,7 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
if (!ignore_acpi_ev && send_acpi_ev) {
acpi_bus_generate_netlink_event(
ibm->acpi->device->pnp.device_class,
- ibm->acpi->device->dev.bus_id,
+ dev_name(&ibm->acpi->device->dev),
event, hkey);
}
}
@@ -2545,7 +2862,7 @@ static int hotkey_read(char *p)
return len;
}
- if (mutex_lock_interruptible(&hotkey_mutex))
+ if (mutex_lock_killable(&hotkey_mutex))
return -ERESTARTSYS;
res = hotkey_status_get(&status);
if (!res)
@@ -2576,7 +2893,7 @@ static int hotkey_write(char *buf)
if (!tp_features.hotkey)
return -ENODEV;
- if (mutex_lock_interruptible(&hotkey_mutex))
+ if (mutex_lock_killable(&hotkey_mutex))
return -ERESTARTSYS;
status = -1;
@@ -2641,11 +2958,28 @@ enum {
/* ACPI GBDC/SBDC bits */
TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
- TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */
+ TP_ACPI_BLUETOOTH_RESUMECTRL = 0x04, /* Bluetooth state at resume:
+ off / last state */
+};
+
+enum {
+ /* ACPI \BLTH commands */
+ TP_ACPI_BLTH_GET_ULTRAPORT_ID = 0x00, /* Get Ultraport BT ID */
+ TP_ACPI_BLTH_GET_PWR_ON_RESUME = 0x01, /* Get power-on-resume state */
+ TP_ACPI_BLTH_PWR_ON_ON_RESUME = 0x02, /* Resume powered on */
+ TP_ACPI_BLTH_PWR_OFF_ON_RESUME = 0x03, /* Resume powered off */
+ TP_ACPI_BLTH_SAVE_STATE = 0x05, /* Save state for S4/S5 */
};
static struct rfkill *tpacpi_bluetooth_rfkill;
+static void bluetooth_suspend(pm_message_t state)
+{
+ /* Try to make sure radio will resume powered off */
+ acpi_evalf(NULL, NULL, "\\BLTH", "vd",
+ TP_ACPI_BLTH_PWR_OFF_ON_RESUME);
+}
+
static int bluetooth_get_radiosw(void)
{
int status;
@@ -2657,6 +2991,12 @@ static int bluetooth_get_radiosw(void)
if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
return RFKILL_STATE_HARD_BLOCKED;
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+ if (dbg_bluetoothemul)
+ return (tpacpi_bluetooth_emulstate) ?
+ RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
+#endif
+
if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
return -EIO;
@@ -2690,12 +3030,20 @@ static int bluetooth_set_radiosw(int radio_on, int update_rfk)
&& radio_on)
return -EPERM;
- if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
- return -EIO;
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+ if (dbg_bluetoothemul) {
+ tpacpi_bluetooth_emulstate = !!radio_on;
+ if (update_rfk)
+ bluetooth_update_rfk();
+ return 0;
+ }
+#endif
+
+ /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */
if (radio_on)
- status |= TP_ACPI_BLUETOOTH_RADIOSSW;
+ status = TP_ACPI_BLUETOOTH_RADIOSSW;
else
- status &= ~TP_ACPI_BLUETOOTH_RADIOSSW;
+ status = 0;
if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
return -EIO;
@@ -2766,8 +3114,19 @@ static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state)
return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
}
+static void bluetooth_shutdown(void)
+{
+ /* Order firmware to save current state to NVRAM */
+ if (!acpi_evalf(NULL, NULL, "\\BLTH", "vd",
+ TP_ACPI_BLTH_SAVE_STATE))
+ printk(TPACPI_NOTICE
+ "failed to save bluetooth state to NVRAM\n");
+}
+
static void bluetooth_exit(void)
{
+ bluetooth_shutdown();
+
if (tpacpi_bluetooth_rfkill)
rfkill_unregister(tpacpi_bluetooth_rfkill);
@@ -2793,6 +3152,13 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
str_supported(tp_features.bluetooth),
status);
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+ if (dbg_bluetoothemul) {
+ tp_features.bluetooth = 1;
+ printk(TPACPI_INFO
+ "bluetooth switch emulation enabled\n");
+ } else
+#endif
if (tp_features.bluetooth &&
!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) {
/* no bluetooth hardware present in system */
@@ -2813,6 +3179,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
&tpacpi_bluetooth_rfkill,
RFKILL_TYPE_BLUETOOTH,
"tpacpi_bluetooth_sw",
+ true,
tpacpi_bluetooth_rfk_set,
tpacpi_bluetooth_rfk_get);
if (res) {
@@ -2865,6 +3232,8 @@ static struct ibm_struct bluetooth_driver_data = {
.read = bluetooth_read,
.write = bluetooth_write,
.exit = bluetooth_exit,
+ .suspend = bluetooth_suspend,
+ .shutdown = bluetooth_shutdown,
};
/*************************************************************************
@@ -2875,11 +3244,19 @@ enum {
/* ACPI GWAN/SWAN bits */
TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
- TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */
+ TP_ACPI_WANCARD_RESUMECTRL = 0x04, /* Wan state at resume:
+ off / last state */
};
static struct rfkill *tpacpi_wan_rfkill;
+static void wan_suspend(pm_message_t state)
+{
+ /* Try to make sure radio will resume powered off */
+ acpi_evalf(NULL, NULL, "\\WGSV", "qvd",
+ TP_ACPI_WGSV_PWR_OFF_ON_RESUME);
+}
+
static int wan_get_radiosw(void)
{
int status;
@@ -2891,6 +3268,12 @@ static int wan_get_radiosw(void)
if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
return RFKILL_STATE_HARD_BLOCKED;
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+ if (dbg_wwanemul)
+ return (tpacpi_wwan_emulstate) ?
+ RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
+#endif
+
if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
return -EIO;
@@ -2924,12 +3307,20 @@ static int wan_set_radiosw(int radio_on, int update_rfk)
&& radio_on)
return -EPERM;
- if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
- return -EIO;
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+ if (dbg_wwanemul) {
+ tpacpi_wwan_emulstate = !!radio_on;
+ if (update_rfk)
+ wan_update_rfk();
+ return 0;
+ }
+#endif
+
+ /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */
if (radio_on)
- status |= TP_ACPI_WANCARD_RADIOSSW;
+ status = TP_ACPI_WANCARD_RADIOSSW;
else
- status &= ~TP_ACPI_WANCARD_RADIOSSW;
+ status = 0;
if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
return -EIO;
@@ -3000,8 +3391,19 @@ static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state)
return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
}
+static void wan_shutdown(void)
+{
+ /* Order firmware to save current state to NVRAM */
+ if (!acpi_evalf(NULL, NULL, "\\WGSV", "vd",
+ TP_ACPI_WGSV_SAVE_STATE))
+ printk(TPACPI_NOTICE
+ "failed to save WWAN state to NVRAM\n");
+}
+
static void wan_exit(void)
{
+ wan_shutdown();
+
if (tpacpi_wan_rfkill)
rfkill_unregister(tpacpi_wan_rfkill);
@@ -3025,6 +3427,13 @@ static int __init wan_init(struct ibm_init_struct *iibm)
str_supported(tp_features.wan),
status);
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+ if (dbg_wwanemul) {
+ tp_features.wan = 1;
+ printk(TPACPI_INFO
+ "wwan switch emulation enabled\n");
+ } else
+#endif
if (tp_features.wan &&
!(status & TP_ACPI_WANCARD_HWPRESENT)) {
/* no wan hardware present in system */
@@ -3045,6 +3454,7 @@ static int __init wan_init(struct ibm_init_struct *iibm)
&tpacpi_wan_rfkill,
RFKILL_TYPE_WWAN,
"tpacpi_wwan_sw",
+ true,
tpacpi_wan_rfk_set,
tpacpi_wan_rfk_get);
if (res) {
@@ -3097,6 +3507,164 @@ static struct ibm_struct wan_driver_data = {
.read = wan_read,
.write = wan_write,
.exit = wan_exit,
+ .suspend = wan_suspend,
+ .shutdown = wan_shutdown,
+};
+
+/*************************************************************************
+ * UWB subdriver
+ */
+
+enum {
+ /* ACPI GUWB/SUWB bits */
+ TP_ACPI_UWB_HWPRESENT = 0x01, /* UWB hw available */
+ TP_ACPI_UWB_RADIOSSW = 0x02, /* UWB radio enabled */
+};
+
+static struct rfkill *tpacpi_uwb_rfkill;
+
+static int uwb_get_radiosw(void)
+{
+ int status;
+
+ if (!tp_features.uwb)
+ return -ENODEV;
+
+ /* WLSW overrides UWB in firmware/hardware, reflect that */
+ if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
+ return RFKILL_STATE_HARD_BLOCKED;
+
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+ if (dbg_uwbemul)
+ return (tpacpi_uwb_emulstate) ?
+ RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
+#endif
+
+ if (!acpi_evalf(hkey_handle, &status, "GUWB", "d"))
+ return -EIO;
+
+ return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ?
+ RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
+}
+
+static void uwb_update_rfk(void)
+{
+ int status;
+
+ if (!tpacpi_uwb_rfkill)
+ return;
+
+ status = uwb_get_radiosw();
+ if (status < 0)
+ return;
+ rfkill_force_state(tpacpi_uwb_rfkill, status);
+}
+
+static int uwb_set_radiosw(int radio_on, int update_rfk)
+{
+ int status;
+
+ if (!tp_features.uwb)
+ return -ENODEV;
+
+ /* WLSW overrides UWB in firmware/hardware, but there is no
+ * reason to risk weird behaviour. */
+ if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
+ && radio_on)
+ return -EPERM;
+
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+ if (dbg_uwbemul) {
+ tpacpi_uwb_emulstate = !!radio_on;
+ if (update_rfk)
+ uwb_update_rfk();
+ return 0;
+ }
+#endif
+
+ status = (radio_on) ? TP_ACPI_UWB_RADIOSSW : 0;
+ if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status))
+ return -EIO;
+
+ if (update_rfk)
+ uwb_update_rfk();
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state)
+{
+ int uwbs = uwb_get_radiosw();
+
+ if (uwbs < 0)
+ return uwbs;
+
+ *state = uwbs;
+ return 0;
+}
+
+static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state)
+{
+ return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
+}
+
+static void uwb_exit(void)
+{
+ if (tpacpi_uwb_rfkill)
+ rfkill_unregister(tpacpi_uwb_rfkill);
+}
+
+static int __init uwb_init(struct ibm_init_struct *iibm)
+{
+ int res;
+ int status = 0;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing uwb subdriver\n");
+
+ TPACPI_ACPIHANDLE_INIT(hkey);
+
+ tp_features.uwb = hkey_handle &&
+ acpi_evalf(hkey_handle, &status, "GUWB", "qd");
+
+ vdbg_printk(TPACPI_DBG_INIT, "uwb is %s, status 0x%02x\n",
+ str_supported(tp_features.uwb),
+ status);
+
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+ if (dbg_uwbemul) {
+ tp_features.uwb = 1;
+ printk(TPACPI_INFO
+ "uwb switch emulation enabled\n");
+ } else
+#endif
+ if (tp_features.uwb &&
+ !(status & TP_ACPI_UWB_HWPRESENT)) {
+ /* no uwb hardware present in system */
+ tp_features.uwb = 0;
+ dbg_printk(TPACPI_DBG_INIT,
+ "uwb hardware not installed\n");
+ }
+
+ if (!tp_features.uwb)
+ return 1;
+
+ res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID,
+ &tpacpi_uwb_rfkill,
+ RFKILL_TYPE_UWB,
+ "tpacpi_uwb_sw",
+ false,
+ tpacpi_uwb_rfk_set,
+ tpacpi_uwb_rfk_get);
+
+ return res;
+}
+
+static struct ibm_struct uwb_driver_data = {
+ .name = "uwb",
+ .exit = uwb_exit,
+ .flags.experimental = 1,
};
/*************************************************************************
@@ -3725,7 +4293,7 @@ static void dock_notify(struct ibm_struct *ibm, u32 event)
}
acpi_bus_generate_proc_event(ibm->acpi->device, event, data);
acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
- ibm->acpi->device->dev.bus_id,
+ dev_name(&ibm->acpi->device->dev),
event, data);
}
@@ -3827,7 +4395,7 @@ static void bay_notify(struct ibm_struct *ibm, u32 event)
{
acpi_bus_generate_proc_event(ibm->acpi->device, event, 0);
acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
- ibm->acpi->device->dev.bus_id,
+ dev_name(&ibm->acpi->device->dev),
event, 0);
}
@@ -4851,7 +5419,7 @@ static int brightness_set(int value)
value < 0)
return -EINVAL;
- res = mutex_lock_interruptible(&brightness_mutex);
+ res = mutex_lock_killable(&brightness_mutex);
if (res < 0)
return res;
@@ -5335,6 +5903,60 @@ TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */
); /* all others */
/*
+ * Unitialized HFSP quirk: ACPI DSDT and EC fail to initialize the
+ * HFSP register at boot, so it contains 0x07 but the Thinkpad could
+ * be in auto mode (0x80).
+ *
+ * This is corrected by any write to HFSP either by the driver, or
+ * by the firmware.
+ *
+ * We assume 0x07 really means auto mode while this quirk is active,
+ * as this is far more likely than the ThinkPad being in level 7,
+ * which is only used by the firmware during thermal emergencies.
+ */
+
+static void fan_quirk1_detect(void)
+{
+ /* In some ThinkPads, neither the EC nor the ACPI
+ * DSDT initialize the HFSP register, and it ends up
+ * being initially set to 0x07 when it *could* be
+ * either 0x07 or 0x80.
+ *
+ * Enable for TP-1Y (T43), TP-78 (R51e),
+ * TP-76 (R52), TP-70 (T43, R52), which are known
+ * to be buggy. */
+ if (fan_control_initial_status == 0x07) {
+ switch (thinkpad_id.ec_model) {
+ case 0x5931: /* TP-1Y */
+ case 0x3837: /* TP-78 */
+ case 0x3637: /* TP-76 */
+ case 0x3037: /* TP-70 */
+ printk(TPACPI_NOTICE
+ "fan_init: initial fan status is unknown, "
+ "assuming it is in auto mode\n");
+ tp_features.fan_ctrl_status_undef = 1;
+ ;;
+ }
+ }
+}
+
+static void fan_quirk1_handle(u8 *fan_status)
+{
+ if (unlikely(tp_features.fan_ctrl_status_undef)) {
+ if (*fan_status != fan_control_initial_status) {
+ /* something changed the HFSP regisnter since
+ * driver init time, so it is not undefined
+ * anymore */
+ tp_features.fan_ctrl_status_undef = 0;
+ } else {
+ /* Return most likely status. In fact, it
+ * might be the only possible status */
+ *fan_status = TP_EC_FAN_AUTO;
+ }
+ }
+}
+
+/*
* Call with fan_mutex held
*/
static void fan_update_desired_level(u8 status)
@@ -5372,8 +5994,10 @@ static int fan_get_status(u8 *status)
if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
return -EIO;
- if (likely(status))
+ if (likely(status)) {
*status = s;
+ fan_quirk1_handle(status);
+ }
break;
@@ -5389,7 +6013,7 @@ static int fan_get_status_safe(u8 *status)
int rc;
u8 s;
- if (mutex_lock_interruptible(&fan_mutex))
+ if (mutex_lock_killable(&fan_mutex))
return -ERESTARTSYS;
rc = fan_get_status(&s);
if (!rc)
@@ -5472,7 +6096,7 @@ static int fan_set_level_safe(int level)
if (!fan_control_allowed)
return -EPERM;
- if (mutex_lock_interruptible(&fan_mutex))
+ if (mutex_lock_killable(&fan_mutex))
return -ERESTARTSYS;
if (level == TPACPI_FAN_LAST_LEVEL)
@@ -5494,7 +6118,7 @@ static int fan_set_enable(void)
if (!fan_control_allowed)
return -EPERM;
- if (mutex_lock_interruptible(&fan_mutex))
+ if (mutex_lock_killable(&fan_mutex))
return -ERESTARTSYS;
switch (fan_control_access_mode) {
@@ -5549,7 +6173,7 @@ static int fan_set_disable(void)
if (!fan_control_allowed)
return -EPERM;
- if (mutex_lock_interruptible(&fan_mutex))
+ if (mutex_lock_killable(&fan_mutex))
return -ERESTARTSYS;
rc = 0;
@@ -5587,7 +6211,7 @@ static int fan_set_speed(int speed)
if (!fan_control_allowed)
return -EPERM;
- if (mutex_lock_interruptible(&fan_mutex))
+ if (mutex_lock_killable(&fan_mutex))
return -ERESTARTSYS;
rc = 0;
@@ -5683,16 +6307,6 @@ static ssize_t fan_pwm1_enable_show(struct device *dev,
if (res)
return res;
- if (unlikely(tp_features.fan_ctrl_status_undef)) {
- if (status != fan_control_initial_status) {
- tp_features.fan_ctrl_status_undef = 0;
- } else {
- /* Return most likely status. In fact, it
- * might be the only possible status */
- status = TP_EC_FAN_AUTO;
- }
- }
-
if (status & TP_EC_FAN_FULLSPEED) {
mode = 0;
} else if (status & TP_EC_FAN_AUTO) {
@@ -5757,14 +6371,6 @@ static ssize_t fan_pwm1_show(struct device *dev,
if (res)
return res;
- if (unlikely(tp_features.fan_ctrl_status_undef)) {
- if (status != fan_control_initial_status) {
- tp_features.fan_ctrl_status_undef = 0;
- } else {
- status = TP_EC_FAN_AUTO;
- }
- }
-
if ((status &
(TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0)
status = fan_control_desired_level;
@@ -5789,7 +6395,7 @@ static ssize_t fan_pwm1_store(struct device *dev,
/* scale down from 0-255 to 0-7 */
newlevel = (s >> 5) & 0x07;
- if (mutex_lock_interruptible(&fan_mutex))
+ if (mutex_lock_killable(&fan_mutex))
return -ERESTARTSYS;
rc = fan_get_status(&status);
@@ -5896,29 +6502,7 @@ static int __init fan_init(struct ibm_init_struct *iibm)
if (likely(acpi_ec_read(fan_status_offset,
&fan_control_initial_status))) {
fan_status_access_mode = TPACPI_FAN_RD_TPEC;
-
- /* In some ThinkPads, neither the EC nor the ACPI
- * DSDT initialize the fan status, and it ends up
- * being set to 0x07 when it *could* be either
- * 0x07 or 0x80.
- *
- * Enable for TP-1Y (T43), TP-78 (R51e),
- * TP-76 (R52), TP-70 (T43, R52), which are known
- * to be buggy. */
- if (fan_control_initial_status == 0x07) {
- switch (thinkpad_id.ec_model) {
- case 0x5931: /* TP-1Y */
- case 0x3837: /* TP-78 */
- case 0x3637: /* TP-76 */
- case 0x3037: /* TP-70 */
- printk(TPACPI_NOTICE
- "fan_init: initial fan status "
- "is unknown, assuming it is "
- "in auto mode\n");
- tp_features.fan_ctrl_status_undef = 1;
- ;;
- }
- }
+ fan_quirk1_detect();
} else {
printk(TPACPI_ERR
"ThinkPad ACPI EC access misbehaving, "
@@ -6107,15 +6691,6 @@ static int fan_read(char *p)
if (rc < 0)
return rc;
- if (unlikely(tp_features.fan_ctrl_status_undef)) {
- if (status != fan_control_initial_status)
- tp_features.fan_ctrl_status_undef = 0;
- else
- /* Return most likely status. In fact, it
- * might be the only possible status */
- status = TP_EC_FAN_AUTO;
- }
-
len += sprintf(p + len, "status:\t\t%s\n",
(status != 0) ? "enabled" : "disabled");
@@ -6564,6 +7139,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
.init = wan_init,
.data = &wan_driver_data,
},
+ {
+ .init = uwb_init,
+ .data = &uwb_driver_data,
+ },
#ifdef CONFIG_THINKPAD_ACPI_VIDEO
{
.init = video_init,
@@ -6702,6 +7281,32 @@ TPACPI_PARAM(brightness);
TPACPI_PARAM(volume);
TPACPI_PARAM(fan);
+#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
+module_param(dbg_wlswemul, uint, 0);
+MODULE_PARM_DESC(dbg_wlswemul, "Enables WLSW emulation");
+module_param_named(wlsw_state, tpacpi_wlsw_emulstate, bool, 0);
+MODULE_PARM_DESC(wlsw_state,
+ "Initial state of the emulated WLSW switch");
+
+module_param(dbg_bluetoothemul, uint, 0);
+MODULE_PARM_DESC(dbg_bluetoothemul, "Enables bluetooth switch emulation");
+module_param_named(bluetooth_state, tpacpi_bluetooth_emulstate, bool, 0);
+MODULE_PARM_DESC(bluetooth_state,
+ "Initial state of the emulated bluetooth switch");
+
+module_param(dbg_wwanemul, uint, 0);
+MODULE_PARM_DESC(dbg_wwanemul, "Enables WWAN switch emulation");
+module_param_named(wwan_state, tpacpi_wwan_emulstate, bool, 0);
+MODULE_PARM_DESC(wwan_state,
+ "Initial state of the emulated WWAN switch");
+
+module_param(dbg_uwbemul, uint, 0);
+MODULE_PARM_DESC(dbg_uwbemul, "Enables UWB switch emulation");
+module_param_named(uwb_state, tpacpi_uwb_emulstate, bool, 0);
+MODULE_PARM_DESC(uwb_state,
+ "Initial state of the emulated UWB switch");
+#endif
+
static void thinkpad_acpi_module_exit(void)
{
struct ibm_struct *ibm, *itmp;
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 40e60fc2e596..40e60fc2e596 100644
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
diff --git a/drivers/acpi/wmi.c b/drivers/platform/x86/wmi.c
index 8a8b377712c9..8a8b377712c9 100644
--- a/drivers/acpi/wmi.c
+++ b/drivers/platform/x86/wmi.c
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 383e47c392a4..2834846a185d 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -23,7 +23,6 @@
#include <linux/pnp.h>
#include <linux/mod_devicetable.h>
#include <acpi/acpi_bus.h>
-#include <acpi/actypes.h>
#include "../base.h"
#include "pnpacpi.h"
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 668472405a57..33da1127992a 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -82,4 +82,10 @@ config BATTERY_DA9030
Say Y here to enable support for batteries charger integrated into
DA9030 PMIC.
+config CHARGER_PCF50633
+ tristate "NXP PCF50633 MBC"
+ depends on MFD_PCF50633
+ help
+ Say Y to include support for NXP PCF50633 Main Battery Charger.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index eebb15505a40..2fcf41d13e5c 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -25,3 +25,4 @@ obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
+obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o \ No newline at end of file
diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c
new file mode 100644
index 000000000000..e988ec130fcd
--- /dev/null
+++ b/drivers/power/pcf50633-charger.c
@@ -0,0 +1,358 @@
+/* NXP PCF50633 Main Battery Charger Driver
+ *
+ * (C) 2006-2008 by Openmoko, Inc.
+ * Author: Balaji Rao <balajirrao@openmoko.org>
+ * All rights reserved.
+ *
+ * Broken down from monstrous PCF50633 driver mainly by
+ * Harald Welte, Andy Green and Werner Almesberger
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+
+#include <linux/mfd/pcf50633/core.h>
+#include <linux/mfd/pcf50633/mbc.h>
+
+struct pcf50633_mbc {
+ struct pcf50633 *pcf;
+
+ int adapter_active;
+ int adapter_online;
+ int usb_active;
+ int usb_online;
+
+ struct power_supply usb;
+ struct power_supply adapter;
+};
+
+int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
+{
+ struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
+ int ret = 0;
+ u8 bits;
+
+ if (ma >= 1000)
+ bits = PCF50633_MBCC7_USB_1000mA;
+ else if (ma >= 500)
+ bits = PCF50633_MBCC7_USB_500mA;
+ else if (ma >= 100)
+ bits = PCF50633_MBCC7_USB_100mA;
+ else
+ bits = PCF50633_MBCC7_USB_SUSPEND;
+
+ ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
+ PCF50633_MBCC7_USB_MASK, bits);
+ if (ret)
+ dev_err(pcf->dev, "error setting usb curlim to %d mA\n", ma);
+ else
+ dev_info(pcf->dev, "usb curlim to %d mA\n", ma);
+
+ power_supply_changed(&mbc->usb);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pcf50633_mbc_usb_curlim_set);
+
+int pcf50633_mbc_get_status(struct pcf50633 *pcf)
+{
+ struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
+ int status = 0;
+
+ if (mbc->usb_online)
+ status |= PCF50633_MBC_USB_ONLINE;
+ if (mbc->usb_active)
+ status |= PCF50633_MBC_USB_ACTIVE;
+ if (mbc->adapter_online)
+ status |= PCF50633_MBC_ADAPTER_ONLINE;
+ if (mbc->adapter_active)
+ status |= PCF50633_MBC_ADAPTER_ACTIVE;
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(pcf50633_mbc_get_status);
+
+void pcf50633_mbc_set_status(struct pcf50633 *pcf, int what, int status)
+{
+ struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
+
+ if (what & PCF50633_MBC_USB_ONLINE)
+ mbc->usb_online = !!status;
+ if (what & PCF50633_MBC_USB_ACTIVE)
+ mbc->usb_active = !!status;
+ if (what & PCF50633_MBC_ADAPTER_ONLINE)
+ mbc->adapter_online = !!status;
+ if (what & PCF50633_MBC_ADAPTER_ACTIVE)
+ mbc->adapter_active = !!status;
+}
+EXPORT_SYMBOL_GPL(pcf50633_mbc_set_status);
+
+static ssize_t
+show_chgmode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
+
+ u8 mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
+ u8 chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);
+
+ return sprintf(buf, "%d\n", chgmod);
+}
+static DEVICE_ATTR(chgmode, S_IRUGO, show_chgmode, NULL);
+
+static ssize_t
+show_usblim(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
+ u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) &
+ PCF50633_MBCC7_USB_MASK;
+ unsigned int ma;
+
+ if (usblim == PCF50633_MBCC7_USB_1000mA)
+ ma = 1000;
+ else if (usblim == PCF50633_MBCC7_USB_500mA)
+ ma = 500;
+ else if (usblim == PCF50633_MBCC7_USB_100mA)
+ ma = 100;
+ else
+ ma = 0;
+
+ return sprintf(buf, "%u\n", ma);
+}
+
+static ssize_t set_usblim(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct pcf50633_mbc *mbc = dev_get_drvdata(dev);
+ unsigned long ma;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &ma);
+ if (ret)
+ return -EINVAL;
+
+ pcf50633_mbc_usb_curlim_set(mbc->pcf, ma);
+
+ return count;
+}
+
+static DEVICE_ATTR(usb_curlim, S_IRUGO | S_IWUSR, show_usblim, set_usblim);
+
+static struct attribute *pcf50633_mbc_sysfs_entries[] = {
+ &dev_attr_chgmode.attr,
+ &dev_attr_usb_curlim.attr,
+ NULL,
+};
+
+static struct attribute_group mbc_attr_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = pcf50633_mbc_sysfs_entries,
+};
+
+static void
+pcf50633_mbc_irq_handler(int irq, void *data)
+{
+ struct pcf50633_mbc *mbc = data;
+
+ /* USB */
+ if (irq == PCF50633_IRQ_USBINS) {
+ mbc->usb_online = 1;
+ } else if (irq == PCF50633_IRQ_USBREM) {
+ mbc->usb_online = 0;
+ mbc->usb_active = 0;
+ pcf50633_mbc_usb_curlim_set(mbc->pcf, 0);
+ }
+
+ /* Adapter */
+ if (irq == PCF50633_IRQ_ADPINS) {
+ mbc->adapter_online = 1;
+ mbc->adapter_active = 1;
+ } else if (irq == PCF50633_IRQ_ADPREM) {
+ mbc->adapter_online = 0;
+ mbc->adapter_active = 0;
+ }
+
+ if (irq == PCF50633_IRQ_BATFULL) {
+ mbc->usb_active = 0;
+ mbc->adapter_active = 0;
+ }
+
+ power_supply_changed(&mbc->usb);
+ power_supply_changed(&mbc->adapter);
+
+ if (mbc->pcf->pdata->mbc_event_callback)
+ mbc->pcf->pdata->mbc_event_callback(mbc->pcf, irq);
+}
+
+static int adapter_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct pcf50633_mbc *mbc = container_of(psy, struct pcf50633_mbc, usb);
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = mbc->adapter_online;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int usb_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct pcf50633_mbc *mbc = container_of(psy, struct pcf50633_mbc, usb);
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = mbc->usb_online;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static enum power_supply_property power_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+};
+
+static const u8 mbc_irq_handlers[] = {
+ PCF50633_IRQ_ADPINS,
+ PCF50633_IRQ_ADPREM,
+ PCF50633_IRQ_USBINS,
+ PCF50633_IRQ_USBREM,
+ PCF50633_IRQ_BATFULL,
+ PCF50633_IRQ_CHGHALT,
+ PCF50633_IRQ_THLIMON,
+ PCF50633_IRQ_THLIMOFF,
+ PCF50633_IRQ_USBLIMON,
+ PCF50633_IRQ_USBLIMOFF,
+ PCF50633_IRQ_LOWSYS,
+ PCF50633_IRQ_LOWBAT,
+};
+
+static int __devinit pcf50633_mbc_probe(struct platform_device *pdev)
+{
+ struct pcf50633_mbc *mbc;
+ struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
+ int ret;
+ int i;
+ u8 mbcs1;
+
+ mbc = kzalloc(sizeof(*mbc), GFP_KERNEL);
+ if (!mbc)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, mbc);
+ mbc->pcf = pdata->pcf;
+
+ /* Set up IRQ handlers */
+ for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
+ pcf50633_register_irq(mbc->pcf, mbc_irq_handlers[i],
+ pcf50633_mbc_irq_handler, mbc);
+
+ /* Create power supplies */
+ mbc->adapter.name = "adapter";
+ mbc->adapter.type = POWER_SUPPLY_TYPE_MAINS;
+ mbc->adapter.properties = power_props;
+ mbc->adapter.num_properties = ARRAY_SIZE(power_props);
+ mbc->adapter.get_property = &adapter_get_property;
+ mbc->adapter.supplied_to = mbc->pcf->pdata->batteries;
+ mbc->adapter.num_supplicants = mbc->pcf->pdata->num_batteries;
+
+ mbc->usb.name = "usb";
+ mbc->usb.type = POWER_SUPPLY_TYPE_USB;
+ mbc->usb.properties = power_props;
+ mbc->usb.num_properties = ARRAY_SIZE(power_props);
+ mbc->usb.get_property = usb_get_property;
+ mbc->usb.supplied_to = mbc->pcf->pdata->batteries;
+ mbc->usb.num_supplicants = mbc->pcf->pdata->num_batteries;
+
+ ret = power_supply_register(&pdev->dev, &mbc->adapter);
+ if (ret) {
+ dev_err(mbc->pcf->dev, "failed to register adapter\n");
+ kfree(mbc);
+ return ret;
+ }
+
+ ret = power_supply_register(&pdev->dev, &mbc->usb);
+ if (ret) {
+ dev_err(mbc->pcf->dev, "failed to register usb\n");
+ power_supply_unregister(&mbc->adapter);
+ kfree(mbc);
+ return ret;
+ }
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group);
+ if (ret)
+ dev_err(mbc->pcf->dev, "failed to create sysfs entries\n");
+
+ mbcs1 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS1);
+ if (mbcs1 & PCF50633_MBCS1_USBPRES)
+ pcf50633_mbc_irq_handler(PCF50633_IRQ_USBINS, mbc);
+ if (mbcs1 & PCF50633_MBCS1_ADAPTPRES)
+ pcf50633_mbc_irq_handler(PCF50633_IRQ_ADPINS, mbc);
+
+ return 0;
+}
+
+static int __devexit pcf50633_mbc_remove(struct platform_device *pdev)
+{
+ struct pcf50633_mbc *mbc = platform_get_drvdata(pdev);
+ int i;
+
+ /* Remove IRQ handlers */
+ for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++)
+ pcf50633_free_irq(mbc->pcf, mbc_irq_handlers[i]);
+
+ power_supply_unregister(&mbc->usb);
+ power_supply_unregister(&mbc->adapter);
+
+ kfree(mbc);
+
+ return 0;
+}
+
+static struct platform_driver pcf50633_mbc_driver = {
+ .driver = {
+ .name = "pcf50633-mbc",
+ },
+ .probe = pcf50633_mbc_probe,
+ .remove = __devexit_p(pcf50633_mbc_remove),
+};
+
+static int __init pcf50633_mbc_init(void)
+{
+ return platform_driver_register(&pcf50633_mbc_driver);
+}
+module_init(pcf50633_mbc_init);
+
+static void __exit pcf50633_mbc_exit(void)
+{
+ platform_driver_unregister(&pcf50633_mbc_driver);
+}
+module_exit(pcf50633_mbc_exit);
+
+MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
+MODULE_DESCRIPTION("PCF50633 mbc driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcf50633-mbc");
diff --git a/drivers/ps3/ps3-lpm.c b/drivers/ps3/ps3-lpm.c
index 204158cf7a55..fe96793e3f08 100644
--- a/drivers/ps3/ps3-lpm.c
+++ b/drivers/ps3/ps3-lpm.c
@@ -732,7 +732,7 @@ static u64 pm_signal_group_to_ps3_lv1_signal_group(u64 group)
case 8:
return pm_translate_signal_group_number_on_island8(subgroup);
default:
- dev_dbg(sbd_core(), "%s:%u: island not found: %lu\n", __func__,
+ dev_dbg(sbd_core(), "%s:%u: island not found: %llu\n", __func__,
__LINE__, group);
BUG();
break;
@@ -765,7 +765,7 @@ static int __ps3_set_signal(u64 lv1_signal_group, u64 bus_select,
signal_select, attr1, attr2, attr3);
if (ret)
dev_err(sbd_core(),
- "%s:%u: error:%d 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
+ "%s:%u: error:%d 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx 0x%llx\n",
__func__, __LINE__, ret, lv1_signal_group, bus_select,
signal_select, attr1, attr2, attr3);
@@ -908,7 +908,7 @@ void ps3_disable_pm(u32 cpu)
lpm_priv->tb_count = tmp;
- dev_dbg(sbd_core(), "%s:%u: tb_count %lu (%lxh)\n", __func__, __LINE__,
+ dev_dbg(sbd_core(), "%s:%u: tb_count %llu (%llxh)\n", __func__, __LINE__,
lpm_priv->tb_count, lpm_priv->tb_count);
}
EXPORT_SYMBOL_GPL(ps3_disable_pm);
@@ -938,7 +938,7 @@ int ps3_lpm_copy_tb(unsigned long offset, void *buf, unsigned long count,
if (offset >= lpm_priv->tb_count)
return 0;
- count = min(count, lpm_priv->tb_count - offset);
+ count = min_t(u64, count, lpm_priv->tb_count - offset);
while (*bytes_copied < count) {
const unsigned long request = count - *bytes_copied;
@@ -993,7 +993,7 @@ int ps3_lpm_copy_tb_to_user(unsigned long offset, void __user *buf,
if (offset >= lpm_priv->tb_count)
return 0;
- count = min(count, lpm_priv->tb_count - offset);
+ count = min_t(u64, count, lpm_priv->tb_count - offset);
while (*bytes_copied < count) {
const unsigned long request = count - *bytes_copied;
@@ -1013,7 +1013,7 @@ int ps3_lpm_copy_tb_to_user(unsigned long offset, void __user *buf,
result = copy_to_user(buf, lpm_priv->tb_cache, tmp);
if (result) {
- dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%p\n",
+ dev_dbg(sbd_core(), "%s:%u: 0x%llx bytes at 0x%p\n",
__func__, __LINE__, tmp, buf);
dev_err(sbd_core(), "%s:%u: copy_to_user failed: %d\n",
__func__, __LINE__, result);
@@ -1148,8 +1148,8 @@ int ps3_lpm_open(enum ps3_lpm_tb_type tb_type, void *tb_cache,
lpm_priv->shadow.group_control = PS3_LPM_SHADOW_REG_INIT;
lpm_priv->shadow.debug_bus_control = PS3_LPM_SHADOW_REG_INIT;
- dev_dbg(sbd_core(), "%s:%u: lpm_id 0x%lx, outlet_id 0x%lx, "
- "tb_size 0x%lx\n", __func__, __LINE__, lpm_priv->lpm_id,
+ dev_dbg(sbd_core(), "%s:%u: lpm_id 0x%llx, outlet_id 0x%llx, "
+ "tb_size 0x%llx\n", __func__, __LINE__, lpm_priv->lpm_id,
lpm_priv->outlet_id, tb_size);
return 0;
diff --git a/drivers/ps3/ps3-vuart.c b/drivers/ps3/ps3-vuart.c
index 90c097a7a47a..e4ad5ba5d0a3 100644
--- a/drivers/ps3/ps3-vuart.c
+++ b/drivers/ps3/ps3-vuart.c
@@ -114,7 +114,7 @@ struct ports_bmp {
static void __maybe_unused _dump_ports_bmp(
const struct ports_bmp *bmp, const char *func, int line)
{
- pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status);
+ pr_debug("%s:%d: ports_bmp: %016llxh\n", func, line, bmp->status);
}
#define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__)
@@ -159,11 +159,13 @@ int ps3_vuart_get_triggers(struct ps3_system_bus_device *dev,
struct vuart_triggers *trig)
{
int result;
- unsigned long size;
- unsigned long val;
+ u64 size;
+ u64 val;
+ u64 tx;
result = lv1_get_virtual_uart_param(dev->port_number,
- PARAM_TX_TRIGGER, &trig->tx);
+ PARAM_TX_TRIGGER, &tx);
+ trig->tx = tx;
if (result) {
dev_dbg(&dev->core, "%s:%d: tx_trigger failed: %s\n",
@@ -201,7 +203,7 @@ int ps3_vuart_set_triggers(struct ps3_system_bus_device *dev, unsigned int tx,
unsigned int rx)
{
int result;
- unsigned long size;
+ u64 size;
result = lv1_set_virtual_uart_param(dev->port_number,
PARAM_TX_TRIGGER, tx);
@@ -248,7 +250,7 @@ static int ps3_vuart_get_rx_bytes_waiting(struct ps3_system_bus_device *dev,
dev_dbg(&dev->core, "%s:%d: rx_bytes failed: %s\n",
__func__, __LINE__, ps3_result(result));
- dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__,
+ dev_dbg(&dev->core, "%s:%d: %llxh\n", __func__, __LINE__,
*bytes_waiting);
return result;
}
@@ -295,7 +297,7 @@ static int ps3_vuart_get_interrupt_status(struct ps3_system_bus_device *dev,
*status = tmp & priv->interrupt_mask;
- dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n",
+ dev_dbg(&dev->core, "%s:%d: m %llxh, s %llxh, m&s %lxh\n",
__func__, __LINE__, priv->interrupt_mask, tmp, *status);
return result;
@@ -363,7 +365,7 @@ int ps3_vuart_disable_interrupt_disconnect(struct ps3_system_bus_device *dev)
*/
static int ps3_vuart_raw_write(struct ps3_system_bus_device *dev,
- const void *buf, unsigned int bytes, unsigned long *bytes_written)
+ const void *buf, unsigned int bytes, u64 *bytes_written)
{
int result;
struct ps3_vuart_port_priv *priv = to_port_priv(dev);
@@ -379,7 +381,7 @@ static int ps3_vuart_raw_write(struct ps3_system_bus_device *dev,
priv->stats.bytes_written += *bytes_written;
- dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__, __LINE__,
+ dev_dbg(&dev->core, "%s:%d: wrote %llxh/%xh=>%lxh\n", __func__, __LINE__,
*bytes_written, bytes, priv->stats.bytes_written);
return result;
@@ -393,7 +395,7 @@ static int ps3_vuart_raw_write(struct ps3_system_bus_device *dev,
*/
static int ps3_vuart_raw_read(struct ps3_system_bus_device *dev, void *buf,
- unsigned int bytes, unsigned long *bytes_read)
+ unsigned int bytes, u64 *bytes_read)
{
int result;
struct ps3_vuart_port_priv *priv = to_port_priv(dev);
@@ -411,7 +413,7 @@ static int ps3_vuart_raw_read(struct ps3_system_bus_device *dev, void *buf,
priv->stats.bytes_read += *bytes_read;
- dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__,
+ dev_dbg(&dev->core, "%s:%d: read %llxh/%xh=>%lxh\n", __func__, __LINE__,
*bytes_read, bytes, priv->stats.bytes_read);
return result;
@@ -500,7 +502,7 @@ int ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf,
spin_lock_irqsave(&priv->tx_list.lock, flags);
if (list_empty(&priv->tx_list.head)) {
- unsigned long bytes_written;
+ u64 bytes_written;
result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written);
@@ -592,7 +594,7 @@ static int ps3_vuart_queue_rx_bytes(struct ps3_system_bus_device *dev,
list_add_tail(&lb->link, &priv->rx_list.head);
priv->rx_list.bytes_held += bytes;
- dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n",
+ dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %llxh bytes\n",
__func__, __LINE__, lb->dbg_number, bytes);
*bytes_queued = bytes;
@@ -745,7 +747,7 @@ static int ps3_vuart_handle_interrupt_tx(struct ps3_system_bus_device *dev)
list_for_each_entry_safe(lb, n, &priv->tx_list.head, link) {
- unsigned long bytes_written;
+ u64 bytes_written;
result = ps3_vuart_raw_write(dev, lb->head, lb->tail - lb->head,
&bytes_written);
@@ -762,7 +764,7 @@ static int ps3_vuart_handle_interrupt_tx(struct ps3_system_bus_device *dev)
if (bytes_written < lb->tail - lb->head) {
lb->head += bytes_written;
dev_dbg(&dev->core,
- "%s:%d cleared buf_%lu, %lxh bytes\n",
+ "%s:%d cleared buf_%lu, %llxh bytes\n",
__func__, __LINE__, lb->dbg_number,
bytes_written);
goto port_full;
diff --git a/drivers/ps3/ps3stor_lib.c b/drivers/ps3/ps3stor_lib.c
index 55955f16ad91..18066d555397 100644
--- a/drivers/ps3/ps3stor_lib.c
+++ b/drivers/ps3/ps3stor_lib.c
@@ -70,7 +70,7 @@ static int ps3stor_probe_access(struct ps3_storage_device *dev)
__func__, __LINE__, n);
dev->region_idx = __ffs(dev->accessible_regions);
dev_info(&dev->sbd.core,
- "First accessible region has index %u start %lu size %lu\n",
+ "First accessible region has index %u start %llu size %llu\n",
dev->region_idx, dev->regions[dev->region_idx].start,
dev->regions[dev->region_idx].size);
@@ -220,7 +220,7 @@ u64 ps3stor_read_write_sectors(struct ps3_storage_device *dev, u64 lpar,
const char *op = write ? "write" : "read";
int res;
- dev_dbg(&dev->sbd.core, "%s:%u: %s %lu sectors starting at %lu\n",
+ dev_dbg(&dev->sbd.core, "%s:%u: %s %llu sectors starting at %llu\n",
__func__, __LINE__, op, sectors, start_sector);
init_completion(&dev->done);
@@ -238,7 +238,7 @@ u64 ps3stor_read_write_sectors(struct ps3_storage_device *dev, u64 lpar,
wait_for_completion(&dev->done);
if (dev->lv1_status) {
- dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+ dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
__LINE__, op, dev->lv1_status);
return dev->lv1_status;
}
@@ -268,7 +268,7 @@ u64 ps3stor_send_command(struct ps3_storage_device *dev, u64 cmd, u64 arg1,
{
int res;
- dev_dbg(&dev->sbd.core, "%s:%u: send device command 0x%lx\n", __func__,
+ dev_dbg(&dev->sbd.core, "%s:%u: send device command 0x%llx\n", __func__,
__LINE__, cmd);
init_completion(&dev->done);
@@ -277,19 +277,19 @@ u64 ps3stor_send_command(struct ps3_storage_device *dev, u64 cmd, u64 arg1,
arg2, arg3, arg4, &dev->tag);
if (res) {
dev_err(&dev->sbd.core,
- "%s:%u: send_device_command 0x%lx failed %d\n",
+ "%s:%u: send_device_command 0x%llx failed %d\n",
__func__, __LINE__, cmd, res);
return -1;
}
wait_for_completion(&dev->done);
if (dev->lv1_status) {
- dev_dbg(&dev->sbd.core, "%s:%u: command 0x%lx failed 0x%lx\n",
+ dev_dbg(&dev->sbd.core, "%s:%u: command 0x%llx failed 0x%llx\n",
__func__, __LINE__, cmd, dev->lv1_status);
return dev->lv1_status;
}
- dev_dbg(&dev->sbd.core, "%s:%u: command 0x%lx completed\n", __func__,
+ dev_dbg(&dev->sbd.core, "%s:%u: command 0x%llx completed\n", __func__,
__LINE__, cmd);
return 0;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 39360e2a4540..e7e0cf102d6d 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -73,4 +73,11 @@ config REGULATOR_DA903X
Say y here to support the BUCKs and LDOs regulators found on
Dialog Semiconductor DA9030/DA9034 PMIC.
+config REGULATOR_PCF50633
+ tristate "PCF50633 regulator driver"
+ depends on MFD_PCF50633
+ help
+ Say Y here to support the voltage regulators and convertors
+ on PCF50633
+
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 254d40c02ee8..61b30c6ddecc 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -11,5 +11,6 @@ obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
+obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 02a774424e8d..f511a406fcaa 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -29,7 +29,7 @@ static DEFINE_MUTEX(regulator_list_mutex);
static LIST_HEAD(regulator_list);
static LIST_HEAD(regulator_map_list);
-/**
+/*
* struct regulator_dev
*
* Voltage / Current regulator class device. One for each regulator.
@@ -56,7 +56,7 @@ struct regulator_dev {
void *reg_data; /* regulator_dev data */
};
-/**
+/*
* struct regulator_map
*
* Used to provide symbolic supply names to devices.
@@ -79,7 +79,7 @@ struct regulator {
int uA_load;
int min_uV;
int max_uV;
- int enabled; /* client has called enabled */
+ int enabled; /* count of client enables */
char *supply_name;
struct device_attribute dev_attr;
struct regulator_dev *rdev;
@@ -174,6 +174,16 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
/* operating mode constraint check */
static int regulator_check_mode(struct regulator_dev *rdev, int mode)
{
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ case REGULATOR_MODE_NORMAL:
+ case REGULATOR_MODE_IDLE:
+ case REGULATOR_MODE_STANDBY:
+ break;
+ default:
+ return -EINVAL;
+ }
+
if (!rdev->constraints) {
printk(KERN_ERR "%s: no constraints for %s\n", __func__,
rdev->desc->name);
@@ -232,6 +242,7 @@ static ssize_t regulator_uV_show(struct device *dev,
return ret;
}
+static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL);
static ssize_t regulator_uA_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -240,6 +251,7 @@ static ssize_t regulator_uA_show(struct device *dev,
return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev));
}
+static DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL);
static ssize_t regulator_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -257,12 +269,8 @@ static ssize_t regulator_name_show(struct device *dev,
return sprintf(buf, "%s\n", name);
}
-static ssize_t regulator_opmode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t regulator_print_opmode(char *buf, int mode)
{
- struct regulator_dev *rdev = dev_get_drvdata(dev);
- int mode = _regulator_get_mode(rdev);
-
switch (mode) {
case REGULATOR_MODE_FAST:
return sprintf(buf, "fast\n");
@@ -276,12 +284,17 @@ static ssize_t regulator_opmode_show(struct device *dev,
return sprintf(buf, "unknown\n");
}
-static ssize_t regulator_state_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t regulator_opmode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
- int state = _regulator_is_enabled(rdev);
+ return regulator_print_opmode(buf, _regulator_get_mode(rdev));
+}
+static DEVICE_ATTR(opmode, 0444, regulator_opmode_show, NULL);
+
+static ssize_t regulator_print_state(char *buf, int state)
+{
if (state > 0)
return sprintf(buf, "enabled\n");
else if (state == 0)
@@ -290,6 +303,15 @@ static ssize_t regulator_state_show(struct device *dev,
return sprintf(buf, "unknown\n");
}
+static ssize_t regulator_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+
+ return regulator_print_state(buf, _regulator_is_enabled(rdev));
+}
+static DEVICE_ATTR(state, 0444, regulator_state_show, NULL);
+
static ssize_t regulator_min_uA_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -300,6 +322,7 @@ static ssize_t regulator_min_uA_show(struct device *dev,
return sprintf(buf, "%d\n", rdev->constraints->min_uA);
}
+static DEVICE_ATTR(min_microamps, 0444, regulator_min_uA_show, NULL);
static ssize_t regulator_max_uA_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -311,6 +334,7 @@ static ssize_t regulator_max_uA_show(struct device *dev,
return sprintf(buf, "%d\n", rdev->constraints->max_uA);
}
+static DEVICE_ATTR(max_microamps, 0444, regulator_max_uA_show, NULL);
static ssize_t regulator_min_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -322,6 +346,7 @@ static ssize_t regulator_min_uV_show(struct device *dev,
return sprintf(buf, "%d\n", rdev->constraints->min_uV);
}
+static DEVICE_ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL);
static ssize_t regulator_max_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -333,6 +358,7 @@ static ssize_t regulator_max_uV_show(struct device *dev,
return sprintf(buf, "%d\n", rdev->constraints->max_uV);
}
+static DEVICE_ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL);
static ssize_t regulator_total_uA_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -347,6 +373,7 @@ static ssize_t regulator_total_uA_show(struct device *dev,
mutex_unlock(&rdev->mutex);
return sprintf(buf, "%d\n", uA);
}
+static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL);
static ssize_t regulator_num_users_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -374,153 +401,106 @@ static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
- if (!rdev->constraints)
- return sprintf(buf, "not defined\n");
return sprintf(buf, "%d\n", rdev->constraints->state_mem.uV);
}
+static DEVICE_ATTR(suspend_mem_microvolts, 0444,
+ regulator_suspend_mem_uV_show, NULL);
static ssize_t regulator_suspend_disk_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
- if (!rdev->constraints)
- return sprintf(buf, "not defined\n");
return sprintf(buf, "%d\n", rdev->constraints->state_disk.uV);
}
+static DEVICE_ATTR(suspend_disk_microvolts, 0444,
+ regulator_suspend_disk_uV_show, NULL);
static ssize_t regulator_suspend_standby_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
- if (!rdev->constraints)
- return sprintf(buf, "not defined\n");
return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV);
}
-
-static ssize_t suspend_opmode_show(struct regulator_dev *rdev,
- unsigned int mode, char *buf)
-{
- switch (mode) {
- case REGULATOR_MODE_FAST:
- return sprintf(buf, "fast\n");
- case REGULATOR_MODE_NORMAL:
- return sprintf(buf, "normal\n");
- case REGULATOR_MODE_IDLE:
- return sprintf(buf, "idle\n");
- case REGULATOR_MODE_STANDBY:
- return sprintf(buf, "standby\n");
- }
- return sprintf(buf, "unknown\n");
-}
+static DEVICE_ATTR(suspend_standby_microvolts, 0444,
+ regulator_suspend_standby_uV_show, NULL);
static ssize_t regulator_suspend_mem_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
- if (!rdev->constraints)
- return sprintf(buf, "not defined\n");
- return suspend_opmode_show(rdev,
- rdev->constraints->state_mem.mode, buf);
+ return regulator_print_opmode(buf,
+ rdev->constraints->state_mem.mode);
}
+static DEVICE_ATTR(suspend_mem_mode, 0444,
+ regulator_suspend_mem_mode_show, NULL);
static ssize_t regulator_suspend_disk_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
- if (!rdev->constraints)
- return sprintf(buf, "not defined\n");
- return suspend_opmode_show(rdev,
- rdev->constraints->state_disk.mode, buf);
+ return regulator_print_opmode(buf,
+ rdev->constraints->state_disk.mode);
}
+static DEVICE_ATTR(suspend_disk_mode, 0444,
+ regulator_suspend_disk_mode_show, NULL);
static ssize_t regulator_suspend_standby_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
- if (!rdev->constraints)
- return sprintf(buf, "not defined\n");
- return suspend_opmode_show(rdev,
- rdev->constraints->state_standby.mode, buf);
+ return regulator_print_opmode(buf,
+ rdev->constraints->state_standby.mode);
}
+static DEVICE_ATTR(suspend_standby_mode, 0444,
+ regulator_suspend_standby_mode_show, NULL);
static ssize_t regulator_suspend_mem_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
- if (!rdev->constraints)
- return sprintf(buf, "not defined\n");
-
- if (rdev->constraints->state_mem.enabled)
- return sprintf(buf, "enabled\n");
- else
- return sprintf(buf, "disabled\n");
+ return regulator_print_state(buf,
+ rdev->constraints->state_mem.enabled);
}
+static DEVICE_ATTR(suspend_mem_state, 0444,
+ regulator_suspend_mem_state_show, NULL);
static ssize_t regulator_suspend_disk_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
- if (!rdev->constraints)
- return sprintf(buf, "not defined\n");
-
- if (rdev->constraints->state_disk.enabled)
- return sprintf(buf, "enabled\n");
- else
- return sprintf(buf, "disabled\n");
+ return regulator_print_state(buf,
+ rdev->constraints->state_disk.enabled);
}
+static DEVICE_ATTR(suspend_disk_state, 0444,
+ regulator_suspend_disk_state_show, NULL);
static ssize_t regulator_suspend_standby_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
- if (!rdev->constraints)
- return sprintf(buf, "not defined\n");
-
- if (rdev->constraints->state_standby.enabled)
- return sprintf(buf, "enabled\n");
- else
- return sprintf(buf, "disabled\n");
+ return regulator_print_state(buf,
+ rdev->constraints->state_standby.enabled);
}
+static DEVICE_ATTR(suspend_standby_state, 0444,
+ regulator_suspend_standby_state_show, NULL);
+
+/*
+ * These are the only attributes are present for all regulators.
+ * Other attributes are a function of regulator functionality.
+ */
static struct device_attribute regulator_dev_attrs[] = {
__ATTR(name, 0444, regulator_name_show, NULL),
- __ATTR(microvolts, 0444, regulator_uV_show, NULL),
- __ATTR(microamps, 0444, regulator_uA_show, NULL),
- __ATTR(opmode, 0444, regulator_opmode_show, NULL),
- __ATTR(state, 0444, regulator_state_show, NULL),
- __ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL),
- __ATTR(min_microamps, 0444, regulator_min_uA_show, NULL),
- __ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL),
- __ATTR(max_microamps, 0444, regulator_max_uA_show, NULL),
- __ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL),
__ATTR(num_users, 0444, regulator_num_users_show, NULL),
__ATTR(type, 0444, regulator_type_show, NULL),
- __ATTR(suspend_mem_microvolts, 0444,
- regulator_suspend_mem_uV_show, NULL),
- __ATTR(suspend_disk_microvolts, 0444,
- regulator_suspend_disk_uV_show, NULL),
- __ATTR(suspend_standby_microvolts, 0444,
- regulator_suspend_standby_uV_show, NULL),
- __ATTR(suspend_mem_mode, 0444,
- regulator_suspend_mem_mode_show, NULL),
- __ATTR(suspend_disk_mode, 0444,
- regulator_suspend_disk_mode_show, NULL),
- __ATTR(suspend_standby_mode, 0444,
- regulator_suspend_standby_mode_show, NULL),
- __ATTR(suspend_mem_state, 0444,
- regulator_suspend_mem_state_show, NULL),
- __ATTR(suspend_disk_state, 0444,
- regulator_suspend_disk_state_show, NULL),
- __ATTR(suspend_standby_state, 0444,
- regulator_suspend_standby_state_show, NULL),
__ATTR_NULL,
};
@@ -675,7 +655,8 @@ static void print_constraints(struct regulator_dev *rdev)
/**
* set_machine_constraints - sets regulator constraints
- * @regulator: regulator source
+ * @rdev: regulator source
+ * @constraints: constraints to apply
*
* Allows platform initialisation code to define and constrain
* regulator circuits e.g. valid voltage/current ranges, etc. NOTE:
@@ -750,8 +731,8 @@ out:
/**
* set_supply - set regulator supply regulator
- * @regulator: regulator name
- * @supply: supply regulator name
+ * @rdev: regulator name
+ * @supply_rdev: supply regulator name
*
* Called by platform initialisation code to set the supply regulator for this
* regulator. This ensures that a regulators supply will also be enabled by the
@@ -778,9 +759,9 @@ out:
/**
* set_consumer_device_supply: Bind a regulator to a symbolic supply
- * @regulator: regulator source
- * @dev: device the supply applies to
- * @supply: symbolic name for supply
+ * @rdev: regulator source
+ * @consumer_dev: device the supply applies to
+ * @supply: symbolic name for supply
*
* Allows platform initialisation code to map physical regulator
* sources to symbolic names for supplies for use by devices. Devices
@@ -795,6 +776,20 @@ static int set_consumer_device_supply(struct regulator_dev *rdev,
if (supply == NULL)
return -EINVAL;
+ list_for_each_entry(node, &regulator_map_list, list) {
+ if (consumer_dev != node->dev)
+ continue;
+ if (strcmp(node->supply, supply) != 0)
+ continue;
+
+ dev_dbg(consumer_dev, "%s/%s is '%s' supply; fail %s/%s\n",
+ dev_name(&node->regulator->dev),
+ node->regulator->desc->name,
+ supply,
+ dev_name(&rdev->dev), rdev->desc->name);
+ return -EBUSY;
+ }
+
node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL);
if (node == NULL)
return -ENOMEM;
@@ -963,16 +958,13 @@ void regulator_put(struct regulator *regulator)
if (regulator == NULL || IS_ERR(regulator))
return;
- if (regulator->enabled) {
- printk(KERN_WARNING "Releasing supply %s while enabled\n",
- regulator->supply_name);
- WARN_ON(regulator->enabled);
- regulator_disable(regulator);
- }
-
mutex_lock(&regulator_list_mutex);
rdev = regulator->rdev;
+ if (WARN(regulator->enabled, "Releasing supply %s while enabled\n",
+ regulator->supply_name))
+ _regulator_disable(rdev);
+
/* remove any sysfs entries */
if (regulator->dev) {
sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
@@ -1034,29 +1026,26 @@ static int _regulator_enable(struct regulator_dev *rdev)
* regulator_enable - enable regulator output
* @regulator: regulator source
*
- * Enable the regulator output at the predefined voltage or current value.
+ * Request that the regulator be enabled with the regulator output at
+ * the predefined voltage or current value. Calls to regulator_enable()
+ * must be balanced with calls to regulator_disable().
+ *
* NOTE: the output value can be set by other drivers, boot loader or may be
* hardwired in the regulator.
- * NOTE: calls to regulator_enable() must be balanced with calls to
- * regulator_disable().
*/
int regulator_enable(struct regulator *regulator)
{
- int ret;
-
- if (regulator->enabled) {
- printk(KERN_CRIT "Regulator %s already enabled\n",
- regulator->supply_name);
- WARN_ON(regulator->enabled);
- return 0;
- }
+ struct regulator_dev *rdev = regulator->rdev;
+ int ret = 0;
- mutex_lock(&regulator->rdev->mutex);
- regulator->enabled = 1;
- ret = _regulator_enable(regulator->rdev);
- if (ret != 0)
- regulator->enabled = 0;
- mutex_unlock(&regulator->rdev->mutex);
+ mutex_lock(&rdev->mutex);
+ if (regulator->enabled == 0)
+ ret = _regulator_enable(rdev);
+ else if (regulator->enabled < 0)
+ ret = -EIO;
+ if (ret == 0)
+ regulator->enabled++;
+ mutex_unlock(&rdev->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_enable);
@@ -1100,27 +1089,31 @@ static int _regulator_disable(struct regulator_dev *rdev)
* regulator_disable - disable regulator output
* @regulator: regulator source
*
- * Disable the regulator output voltage or current.
- * NOTE: this will only disable the regulator output if no other consumer
- * devices have it enabled.
- * NOTE: calls to regulator_enable() must be balanced with calls to
+ * Disable the regulator output voltage or current. Calls to
+ * regulator_enable() must be balanced with calls to
* regulator_disable().
+ *
+ * NOTE: this will only disable the regulator output if no other consumer
+ * devices have it enabled, the regulator device supports disabling and
+ * machine constraints permit this operation.
*/
int regulator_disable(struct regulator *regulator)
{
- int ret;
-
- if (!regulator->enabled) {
- printk(KERN_ERR "%s: not in use by this consumer\n",
- __func__);
- return 0;
- }
+ struct regulator_dev *rdev = regulator->rdev;
+ int ret = 0;
- mutex_lock(&regulator->rdev->mutex);
- regulator->enabled = 0;
- regulator->uA_load = 0;
- ret = _regulator_disable(regulator->rdev);
- mutex_unlock(&regulator->rdev->mutex);
+ mutex_lock(&rdev->mutex);
+ if (regulator->enabled == 1) {
+ ret = _regulator_disable(rdev);
+ if (ret == 0)
+ regulator->uA_load = 0;
+ } else if (WARN(regulator->enabled <= 0,
+ "unbalanced disables for supply %s\n",
+ regulator->supply_name))
+ ret = -EIO;
+ if (ret == 0)
+ regulator->enabled--;
+ mutex_unlock(&rdev->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_disable);
@@ -1196,7 +1189,13 @@ out:
* regulator_is_enabled - is the regulator output enabled
* @regulator: regulator source
*
- * Returns zero for disabled otherwise return number of enable requests.
+ * Returns positive if the regulator driver backing the source/client
+ * has requested that the device be enabled, zero if it hasn't, else a
+ * negative errno code.
+ *
+ * Note that the device backing this regulator handle can have multiple
+ * users, so it might be enabled even if regulator_enable() was never
+ * called for this particular source.
*/
int regulator_is_enabled(struct regulator *regulator)
{
@@ -1219,7 +1218,7 @@ EXPORT_SYMBOL_GPL(regulator_is_enabled);
*
* NOTE: If the regulator is shared between several devices then the lowest
* request voltage that meets the system constraints will be used.
- * NOTE: Regulator system constraints must be set for this regulator before
+ * Regulator system constraints must be set for this regulator before
* calling this function otherwise this call will fail.
*/
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
@@ -1493,7 +1492,8 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
mode = rdev->desc->ops->get_optimum_mode(rdev,
input_uV, output_uV,
total_uA_load);
- if (ret <= 0) {
+ ret = regulator_check_mode(rdev, mode);
+ if (ret < 0) {
printk(KERN_ERR "%s: failed to get optimum mode for %s @"
" %d uA %d -> %d uV\n", __func__, rdev->desc->name,
total_uA_load, input_uV, output_uV);
@@ -1501,7 +1501,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
}
ret = rdev->desc->ops->set_mode(rdev, mode);
- if (ret <= 0) {
+ if (ret < 0) {
printk(KERN_ERR "%s: failed to set optimum mode %x for %s\n",
__func__, mode, rdev->desc->name);
goto out;
@@ -1516,7 +1516,7 @@ EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
/**
* regulator_register_notifier - register regulator event notifier
* @regulator: regulator source
- * @notifier_block: notifier block
+ * @nb: notifier block
*
* Register notifier block to receive regulator events.
*/
@@ -1531,7 +1531,7 @@ EXPORT_SYMBOL_GPL(regulator_register_notifier);
/**
* regulator_unregister_notifier - unregister regulator event notifier
* @regulator: regulator source
- * @notifier_block: notifier block
+ * @nb: notifier block
*
* Unregister regulator event notifier block.
*/
@@ -1697,9 +1697,9 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free);
/**
* regulator_notifier_call_chain - call regulator event notifier
- * @regulator: regulator source
+ * @rdev: regulator source
* @event: notifier block
- * @data:
+ * @data: callback-specific data.
*
* Called by regulator drivers to notify clients a regulator event has
* occurred. We also notify regulator clients downstream.
@@ -1713,10 +1713,122 @@ int regulator_notifier_call_chain(struct regulator_dev *rdev,
}
EXPORT_SYMBOL_GPL(regulator_notifier_call_chain);
+/*
+ * To avoid cluttering sysfs (and memory) with useless state, only
+ * create attributes that can be meaningfully displayed.
+ */
+static int add_regulator_attributes(struct regulator_dev *rdev)
+{
+ struct device *dev = &rdev->dev;
+ struct regulator_ops *ops = rdev->desc->ops;
+ int status = 0;
+
+ /* some attributes need specific methods to be displayed */
+ if (ops->get_voltage) {
+ status = device_create_file(dev, &dev_attr_microvolts);
+ if (status < 0)
+ return status;
+ }
+ if (ops->get_current_limit) {
+ status = device_create_file(dev, &dev_attr_microamps);
+ if (status < 0)
+ return status;
+ }
+ if (ops->get_mode) {
+ status = device_create_file(dev, &dev_attr_opmode);
+ if (status < 0)
+ return status;
+ }
+ if (ops->is_enabled) {
+ status = device_create_file(dev, &dev_attr_state);
+ if (status < 0)
+ return status;
+ }
+
+ /* some attributes are type-specific */
+ if (rdev->desc->type == REGULATOR_CURRENT) {
+ status = device_create_file(dev, &dev_attr_requested_microamps);
+ if (status < 0)
+ return status;
+ }
+
+ /* all the other attributes exist to support constraints;
+ * don't show them if there are no constraints, or if the
+ * relevant supporting methods are missing.
+ */
+ if (!rdev->constraints)
+ return status;
+
+ /* constraints need specific supporting methods */
+ if (ops->set_voltage) {
+ status = device_create_file(dev, &dev_attr_min_microvolts);
+ if (status < 0)
+ return status;
+ status = device_create_file(dev, &dev_attr_max_microvolts);
+ if (status < 0)
+ return status;
+ }
+ if (ops->set_current_limit) {
+ status = device_create_file(dev, &dev_attr_min_microamps);
+ if (status < 0)
+ return status;
+ status = device_create_file(dev, &dev_attr_max_microamps);
+ if (status < 0)
+ return status;
+ }
+
+ /* suspend mode constraints need multiple supporting methods */
+ if (!(ops->set_suspend_enable && ops->set_suspend_disable))
+ return status;
+
+ status = device_create_file(dev, &dev_attr_suspend_standby_state);
+ if (status < 0)
+ return status;
+ status = device_create_file(dev, &dev_attr_suspend_mem_state);
+ if (status < 0)
+ return status;
+ status = device_create_file(dev, &dev_attr_suspend_disk_state);
+ if (status < 0)
+ return status;
+
+ if (ops->set_suspend_voltage) {
+ status = device_create_file(dev,
+ &dev_attr_suspend_standby_microvolts);
+ if (status < 0)
+ return status;
+ status = device_create_file(dev,
+ &dev_attr_suspend_mem_microvolts);
+ if (status < 0)
+ return status;
+ status = device_create_file(dev,
+ &dev_attr_suspend_disk_microvolts);
+ if (status < 0)
+ return status;
+ }
+
+ if (ops->set_suspend_mode) {
+ status = device_create_file(dev,
+ &dev_attr_suspend_standby_mode);
+ if (status < 0)
+ return status;
+ status = device_create_file(dev,
+ &dev_attr_suspend_mem_mode);
+ if (status < 0)
+ return status;
+ status = device_create_file(dev,
+ &dev_attr_suspend_disk_mode);
+ if (status < 0)
+ return status;
+ }
+
+ return status;
+}
+
/**
* regulator_register - register regulator
- * @regulator: regulator source
- * @reg_data: private regulator data
+ * @regulator_desc: regulator to register
+ * @dev: struct device for the regulator
+ * @driver_data: private regulator data
*
* Called by regulator drivers to register a regulator.
* Returns 0 on success.
@@ -1761,45 +1873,37 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
/* preform any regulator specific init */
if (init_data->regulator_init) {
ret = init_data->regulator_init(rdev->reg_data);
- if (ret < 0) {
- kfree(rdev);
- rdev = ERR_PTR(ret);
- goto out;
- }
- }
-
- /* set regulator constraints */
- ret = set_machine_constraints(rdev, &init_data->constraints);
- if (ret < 0) {
- kfree(rdev);
- rdev = ERR_PTR(ret);
- goto out;
+ if (ret < 0)
+ goto clean;
}
/* register with sysfs */
rdev->dev.class = &regulator_class;
rdev->dev.parent = dev;
- snprintf(rdev->dev.bus_id, sizeof(rdev->dev.bus_id),
- "regulator.%d", atomic_inc_return(&regulator_no) - 1);
+ dev_set_name(&rdev->dev, "regulator.%d",
+ atomic_inc_return(&regulator_no) - 1);
ret = device_register(&rdev->dev);
- if (ret != 0) {
- kfree(rdev);
- rdev = ERR_PTR(ret);
- goto out;
- }
+ if (ret != 0)
+ goto clean;
dev_set_drvdata(&rdev->dev, rdev);
+ /* set regulator constraints */
+ ret = set_machine_constraints(rdev, &init_data->constraints);
+ if (ret < 0)
+ goto scrub;
+
+ /* add attributes supported by this regulator */
+ ret = add_regulator_attributes(rdev);
+ if (ret < 0)
+ goto scrub;
+
/* set supply regulator if it exists */
if (init_data->supply_regulator_dev) {
ret = set_supply(rdev,
dev_get_drvdata(init_data->supply_regulator_dev));
- if (ret < 0) {
- device_unregister(&rdev->dev);
- kfree(rdev);
- rdev = ERR_PTR(ret);
- goto out;
- }
+ if (ret < 0)
+ goto scrub;
}
/* add consumers devices */
@@ -1811,10 +1915,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
for (--i; i >= 0; i--)
unset_consumer_device_supply(rdev,
init_data->consumer_supplies[i].dev);
- device_unregister(&rdev->dev);
- kfree(rdev);
- rdev = ERR_PTR(ret);
- goto out;
+ goto scrub;
}
}
@@ -1822,12 +1923,19 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
out:
mutex_unlock(&regulator_list_mutex);
return rdev;
+
+scrub:
+ device_unregister(&rdev->dev);
+clean:
+ kfree(rdev);
+ rdev = ERR_PTR(ret);
+ goto out;
}
EXPORT_SYMBOL_GPL(regulator_register);
/**
* regulator_unregister - unregister regulator
- * @regulator: regulator source
+ * @rdev: regulator to unregister
*
* Called by regulator drivers to unregister a regulator.
*/
@@ -1846,7 +1954,7 @@ void regulator_unregister(struct regulator_dev *rdev)
EXPORT_SYMBOL_GPL(regulator_unregister);
/**
- * regulator_suspend_prepare: prepare regulators for system wide suspend
+ * regulator_suspend_prepare - prepare regulators for system wide suspend
* @state: system suspend state
*
* Configure each regulator with it's suspend operating parameters for state.
@@ -1882,7 +1990,7 @@ EXPORT_SYMBOL_GPL(regulator_suspend_prepare);
/**
* rdev_get_drvdata - get rdev regulator driver data
- * @regulator: regulator
+ * @rdev: regulator
*
* Get rdev regulator driver private data. This call can be used in the
* regulator driver context.
@@ -1919,7 +2027,7 @@ EXPORT_SYMBOL_GPL(regulator_set_drvdata);
/**
* regulator_get_id - get regulator ID
- * @regulator: regulator
+ * @rdev: regulator
*/
int rdev_get_id(struct regulator_dev *rdev)
{
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
index 773b29cec8be..fe77730a7edb 100644
--- a/drivers/regulator/da903x.c
+++ b/drivers/regulator/da903x.c
@@ -102,7 +102,7 @@ static int da903x_set_ldo_voltage(struct regulator_dev *rdev,
uint8_t val, mask;
if (check_range(info, min_uV, max_uV)) {
- pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
return -EINVAL;
}
@@ -159,7 +159,7 @@ static int da903x_is_enabled(struct regulator_dev *rdev)
if (ret)
return ret;
- return reg_val & (1 << info->enable_bit);
+ return !!(reg_val & (1 << info->enable_bit));
}
/* DA9030 specific operations */
@@ -172,7 +172,7 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
int ret;
if (check_range(info, min_uV, max_uV)) {
- pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
return -EINVAL;
}
@@ -199,7 +199,7 @@ static int da9030_set_ldo14_voltage(struct regulator_dev *rdev,
int thresh;
if (check_range(info, min_uV, max_uV)) {
- pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
return -EINVAL;
}
@@ -248,7 +248,7 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev,
int ret;
if (check_range(info, min_uV, max_uV)) {
- pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
return -EINVAL;
}
@@ -273,7 +273,7 @@ static int da9034_set_ldo12_voltage(struct regulator_dev *rdev,
uint8_t val, mask;
if (check_range(info, min_uV, max_uV)) {
- pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
return -EINVAL;
}
diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c
new file mode 100644
index 000000000000..4cc85ec6e120
--- /dev/null
+++ b/drivers/regulator/pcf50633-regulator.c
@@ -0,0 +1,329 @@
+/* NXP PCF50633 PMIC Driver
+ *
+ * (C) 2006-2008 by Openmoko, Inc.
+ * Author: Balaji Rao <balajirrao@openmoko.org>
+ * All rights reserved.
+ *
+ * Broken down from monstrous PCF50633 driver mainly by
+ * Harald Welte and Andy Green and Werner Almesberger
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+
+#include <linux/mfd/pcf50633/core.h>
+#include <linux/mfd/pcf50633/pmic.h>
+
+#define PCF50633_REGULATOR(_name, _id) \
+ { \
+ .name = _name, \
+ .id = _id, \
+ .ops = &pcf50633_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }
+
+static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = {
+ [PCF50633_REGULATOR_AUTO] = PCF50633_REG_AUTOOUT,
+ [PCF50633_REGULATOR_DOWN1] = PCF50633_REG_DOWN1OUT,
+ [PCF50633_REGULATOR_DOWN2] = PCF50633_REG_DOWN2OUT,
+ [PCF50633_REGULATOR_MEMLDO] = PCF50633_REG_MEMLDOOUT,
+ [PCF50633_REGULATOR_LDO1] = PCF50633_REG_LDO1OUT,
+ [PCF50633_REGULATOR_LDO2] = PCF50633_REG_LDO2OUT,
+ [PCF50633_REGULATOR_LDO3] = PCF50633_REG_LDO3OUT,
+ [PCF50633_REGULATOR_LDO4] = PCF50633_REG_LDO4OUT,
+ [PCF50633_REGULATOR_LDO5] = PCF50633_REG_LDO5OUT,
+ [PCF50633_REGULATOR_LDO6] = PCF50633_REG_LDO6OUT,
+ [PCF50633_REGULATOR_HCLDO] = PCF50633_REG_HCLDOOUT,
+};
+
+/* Bits from voltage value */
+static u8 auto_voltage_bits(unsigned int millivolts)
+{
+ if (millivolts < 1800)
+ return 0;
+ if (millivolts > 3800)
+ return 0xff;
+
+ millivolts -= 625;
+
+ return millivolts / 25;
+}
+
+static u8 down_voltage_bits(unsigned int millivolts)
+{
+ if (millivolts < 625)
+ return 0;
+ else if (millivolts > 3000)
+ return 0xff;
+
+ millivolts -= 625;
+
+ return millivolts / 25;
+}
+
+static u8 ldo_voltage_bits(unsigned int millivolts)
+{
+ if (millivolts < 900)
+ return 0;
+ else if (millivolts > 3600)
+ return 0x1f;
+
+ millivolts -= 900;
+ return millivolts / 100;
+}
+
+/* Obtain voltage value from bits */
+static unsigned int auto_voltage_value(u8 bits)
+{
+ if (bits < 0x2f)
+ return 0;
+
+ return 625 + (bits * 25);
+}
+
+
+static unsigned int down_voltage_value(u8 bits)
+{
+ return 625 + (bits * 25);
+}
+
+
+static unsigned int ldo_voltage_value(u8 bits)
+{
+ bits &= 0x1f;
+
+ return 900 + (bits * 100);
+}
+
+static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct pcf50633 *pcf;
+ int regulator_id, millivolts;
+ u8 volt_bits, regnr;
+
+ pcf = rdev_get_drvdata(rdev);
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= PCF50633_NUM_REGULATORS)
+ return -EINVAL;
+
+ millivolts = min_uV / 1000;
+
+ regnr = pcf50633_regulator_registers[regulator_id];
+
+ switch (regulator_id) {
+ case PCF50633_REGULATOR_AUTO:
+ volt_bits = auto_voltage_bits(millivolts);
+ break;
+ case PCF50633_REGULATOR_DOWN1:
+ volt_bits = down_voltage_bits(millivolts);
+ break;
+ case PCF50633_REGULATOR_DOWN2:
+ volt_bits = down_voltage_bits(millivolts);
+ break;
+ case PCF50633_REGULATOR_LDO1:
+ case PCF50633_REGULATOR_LDO2:
+ case PCF50633_REGULATOR_LDO3:
+ case PCF50633_REGULATOR_LDO4:
+ case PCF50633_REGULATOR_LDO5:
+ case PCF50633_REGULATOR_LDO6:
+ case PCF50633_REGULATOR_HCLDO:
+ volt_bits = ldo_voltage_bits(millivolts);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return pcf50633_reg_write(pcf, regnr, volt_bits);
+}
+
+static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct pcf50633 *pcf;
+ int regulator_id, millivolts, volt_bits;
+ u8 regnr;
+
+ pcf = rdev_get_drvdata(rdev);;
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= PCF50633_NUM_REGULATORS)
+ return -EINVAL;
+
+ regnr = pcf50633_regulator_registers[regulator_id];
+
+ volt_bits = pcf50633_reg_read(pcf, regnr);
+ if (volt_bits < 0)
+ return -1;
+
+ switch (regulator_id) {
+ case PCF50633_REGULATOR_AUTO:
+ millivolts = auto_voltage_value(volt_bits);
+ break;
+ case PCF50633_REGULATOR_DOWN1:
+ millivolts = down_voltage_value(volt_bits);
+ break;
+ case PCF50633_REGULATOR_DOWN2:
+ millivolts = down_voltage_value(volt_bits);
+ break;
+ case PCF50633_REGULATOR_LDO1:
+ case PCF50633_REGULATOR_LDO2:
+ case PCF50633_REGULATOR_LDO3:
+ case PCF50633_REGULATOR_LDO4:
+ case PCF50633_REGULATOR_LDO5:
+ case PCF50633_REGULATOR_LDO6:
+ case PCF50633_REGULATOR_HCLDO:
+ millivolts = ldo_voltage_value(volt_bits);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return millivolts * 1000;
+}
+
+static int pcf50633_regulator_enable(struct regulator_dev *rdev)
+{
+ struct pcf50633 *pcf = rdev_get_drvdata(rdev);
+ int regulator_id;
+ u8 regnr;
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= PCF50633_NUM_REGULATORS)
+ return -EINVAL;
+
+ /* The *ENA register is always one after the *OUT register */
+ regnr = pcf50633_regulator_registers[regulator_id] + 1;
+
+ return pcf50633_reg_set_bit_mask(pcf, regnr, PCF50633_REGULATOR_ON,
+ PCF50633_REGULATOR_ON);
+}
+
+static int pcf50633_regulator_disable(struct regulator_dev *rdev)
+{
+ struct pcf50633 *pcf = rdev_get_drvdata(rdev);
+ int regulator_id;
+ u8 regnr;
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= PCF50633_NUM_REGULATORS)
+ return -EINVAL;
+
+ /* the *ENA register is always one after the *OUT register */
+ regnr = pcf50633_regulator_registers[regulator_id] + 1;
+
+ return pcf50633_reg_set_bit_mask(pcf, regnr,
+ PCF50633_REGULATOR_ON, 0);
+}
+
+static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct pcf50633 *pcf = rdev_get_drvdata(rdev);
+ int regulator_id = rdev_get_id(rdev);
+ u8 regnr;
+
+ regulator_id = rdev_get_id(rdev);
+ if (regulator_id >= PCF50633_NUM_REGULATORS)
+ return -EINVAL;
+
+ /* the *ENA register is always one after the *OUT register */
+ regnr = pcf50633_regulator_registers[regulator_id] + 1;
+
+ return pcf50633_reg_read(pcf, regnr) & PCF50633_REGULATOR_ON;
+}
+
+static struct regulator_ops pcf50633_regulator_ops = {
+ .set_voltage = pcf50633_regulator_set_voltage,
+ .get_voltage = pcf50633_regulator_get_voltage,
+ .enable = pcf50633_regulator_enable,
+ .disable = pcf50633_regulator_disable,
+ .is_enabled = pcf50633_regulator_is_enabled,
+};
+
+static struct regulator_desc regulators[] = {
+ [PCF50633_REGULATOR_AUTO] =
+ PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO),
+ [PCF50633_REGULATOR_DOWN1] =
+ PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1),
+ [PCF50633_REGULATOR_DOWN2] =
+ PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2),
+ [PCF50633_REGULATOR_LDO1] =
+ PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1),
+ [PCF50633_REGULATOR_LDO2] =
+ PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2),
+ [PCF50633_REGULATOR_LDO3] =
+ PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3),
+ [PCF50633_REGULATOR_LDO4] =
+ PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4),
+ [PCF50633_REGULATOR_LDO5] =
+ PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5),
+ [PCF50633_REGULATOR_LDO6] =
+ PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6),
+ [PCF50633_REGULATOR_HCLDO] =
+ PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO),
+ [PCF50633_REGULATOR_MEMLDO] =
+ PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO),
+};
+
+static int __devinit pcf50633_regulator_probe(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev;
+ struct pcf50633 *pcf;
+
+ /* Already set by core driver */
+ pcf = platform_get_drvdata(pdev);
+
+ rdev = regulator_register(&regulators[pdev->id], &pdev->dev, pcf);
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+ if (pcf->pdata->regulator_registered)
+ pcf->pdata->regulator_registered(pcf, pdev->id);
+
+ return 0;
+}
+
+static int __devexit pcf50633_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+ regulator_unregister(rdev);
+
+ return 0;
+}
+
+static struct platform_driver pcf50633_regulator_driver = {
+ .driver = {
+ .name = "pcf50633-regltr",
+ },
+ .probe = pcf50633_regulator_probe,
+ .remove = __devexit_p(pcf50633_regulator_remove),
+};
+
+static int __init pcf50633_regulator_init(void)
+{
+ return platform_driver_register(&pcf50633_regulator_driver);
+}
+module_init(pcf50633_regulator_init);
+
+static void __exit pcf50633_regulator_exit(void)
+{
+ platform_driver_unregister(&pcf50633_regulator_driver);
+}
+module_exit(pcf50633_regulator_exit);
+
+MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
+MODULE_DESCRIPTION("PCF50633 regulator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcf50633-regulator");
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index c68c496b2c49..7aa35248181b 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -1412,6 +1412,97 @@ int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
}
EXPORT_SYMBOL_GPL(wm8350_register_regulator);
+/**
+ * wm8350_register_led - Register a WM8350 LED output
+ *
+ * @param wm8350 The WM8350 device to configure.
+ * @param lednum LED device index to create.
+ * @param dcdc The DCDC to use for the LED.
+ * @param isink The ISINK to use for the LED.
+ * @param pdata Configuration for the LED.
+ *
+ * The WM8350 supports the use of an ISINK together with a DCDC to
+ * provide a power-efficient LED driver. This function registers the
+ * regulators and instantiates the platform device for a LED. The
+ * operating modes for the LED regulators must be configured using
+ * wm8350_isink_set_flash(), wm8350_dcdc25_set_mode() and
+ * wm8350_dcdc_set_slot() prior to calling this function.
+ */
+int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink,
+ struct wm8350_led_platform_data *pdata)
+{
+ struct wm8350_led *led;
+ struct platform_device *pdev;
+ int ret;
+
+ if (lednum > ARRAY_SIZE(wm8350->pmic.led) || lednum < 0) {
+ dev_err(wm8350->dev, "Invalid LED index %d\n", lednum);
+ return -ENODEV;
+ }
+
+ led = &wm8350->pmic.led[lednum];
+
+ if (led->pdev) {
+ dev_err(wm8350->dev, "LED %d already allocated\n", lednum);
+ return -EINVAL;
+ }
+
+ pdev = platform_device_alloc("wm8350-led", lednum);
+ if (pdev == NULL) {
+ dev_err(wm8350->dev, "Failed to allocate LED %d\n", lednum);
+ return -ENOMEM;
+ }
+
+ led->isink_consumer.dev = &pdev->dev;
+ led->isink_consumer.supply = "led_isink";
+ led->isink_init.num_consumer_supplies = 1;
+ led->isink_init.consumer_supplies = &led->isink_consumer;
+ led->isink_init.constraints.min_uA = 0;
+ led->isink_init.constraints.max_uA = pdata->max_uA;
+ led->isink_init.constraints.valid_ops_mask = REGULATOR_CHANGE_CURRENT;
+ led->isink_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL;
+ ret = wm8350_register_regulator(wm8350, isink, &led->isink_init);
+ if (ret != 0) {
+ platform_device_put(pdev);
+ return ret;
+ }
+
+ led->dcdc_consumer.dev = &pdev->dev;
+ led->dcdc_consumer.supply = "led_vcc";
+ led->dcdc_init.num_consumer_supplies = 1;
+ led->dcdc_init.consumer_supplies = &led->dcdc_consumer;
+ led->dcdc_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL;
+ ret = wm8350_register_regulator(wm8350, dcdc, &led->dcdc_init);
+ if (ret != 0) {
+ platform_device_put(pdev);
+ return ret;
+ }
+
+ switch (isink) {
+ case WM8350_ISINK_A:
+ wm8350->pmic.isink_A_dcdc = dcdc;
+ break;
+ case WM8350_ISINK_B:
+ wm8350->pmic.isink_B_dcdc = dcdc;
+ break;
+ }
+
+ pdev->dev.platform_data = pdata;
+ pdev->dev.parent = wm8350->dev;
+ ret = platform_device_add(pdev);
+ if (ret != 0) {
+ dev_err(wm8350->dev, "Failed to register LED %d: %d\n",
+ lednum, ret);
+ platform_device_put(pdev);
+ return ret;
+ }
+
+ led->pdev = pdev;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_register_led);
+
static struct platform_driver wm8350_regulator_driver = {
.probe = wm8350_regulator_probe,
.remove = wm8350_regulator_remove,
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index 48b372e038a8..56e23d44ba59 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -289,7 +289,7 @@ static struct regulator_desc regulators[] = {
},
};
-static int __init wm8400_regulator_probe(struct platform_device *pdev)
+static int __devinit wm8400_regulator_probe(struct platform_device *pdev)
{
struct regulator_dev *rdev;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 4ad831de41ad..cced4d108319 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -502,6 +502,13 @@ config RTC_DRV_WM8350
This driver can also be built as a module. If so, the module
will be called "rtc-wm8350".
+config RTC_DRV_PCF50633
+ depends on MFD_PCF50633
+ tristate "NXP PCF50633 RTC"
+ help
+ If you say yes here you get support for the RTC subsystem of the
+ NXP PCF50633 used in embedded systems.
+
comment "on-CPU RTC drivers"
config RTC_DRV_OMAP
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 9a4340d48f26..6e28021abb9d 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -74,3 +74,4 @@ obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
+obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 162330b9d1dc..7e5155e88ac7 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -86,13 +86,11 @@ enum ds_type {
struct ds1307 {
- u8 reg_addr;
u8 regs[11];
enum ds_type type;
unsigned long flags;
#define HAS_NVRAM 0 /* bit 0 == sysfs file active */
#define HAS_ALARM 1 /* bit 1 == irq claimed */
- struct i2c_msg msg[2];
struct i2c_client *client;
struct rtc_device *rtc;
struct work_struct work;
@@ -204,13 +202,9 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
int tmp;
/* read the RTC date and time registers all at once */
- ds1307->reg_addr = 0;
- ds1307->msg[1].flags = I2C_M_RD;
- ds1307->msg[1].len = 7;
-
- tmp = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent),
- ds1307->msg, 2);
- if (tmp != 2) {
+ tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
+ DS1307_REG_SECS, 7, ds1307->regs);
+ if (tmp != 7) {
dev_err(dev, "%s error %d\n", "read", tmp);
return -EIO;
}
@@ -257,7 +251,6 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
t->tm_hour, t->tm_mday,
t->tm_mon, t->tm_year, t->tm_wday);
- *buf++ = 0; /* first register addr */
buf[DS1307_REG_SECS] = bin2bcd(t->tm_sec);
buf[DS1307_REG_MIN] = bin2bcd(t->tm_min);
buf[DS1307_REG_HOUR] = bin2bcd(t->tm_hour);
@@ -282,23 +275,19 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
break;
}
- ds1307->msg[1].flags = 0;
- ds1307->msg[1].len = 8;
-
dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
"write", buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6]);
- result = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent),
- &ds1307->msg[1], 1);
- if (result != 1) {
- dev_err(dev, "%s error %d\n", "write", tmp);
- return -EIO;
+ result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf);
+ if (result < 0) {
+ dev_err(dev, "%s error %d\n", "write", result);
+ return result;
}
return 0;
}
-static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
@@ -308,13 +297,9 @@ static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t)
return -EINVAL;
/* read all ALARM1, ALARM2, and status registers at once */
- ds1307->reg_addr = DS1339_REG_ALARM1_SECS;
- ds1307->msg[1].flags = I2C_M_RD;
- ds1307->msg[1].len = 9;
-
- ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
- ds1307->msg, 2);
- if (ret != 2) {
+ ret = i2c_smbus_read_i2c_block_data(client,
+ DS1339_REG_ALARM1_SECS, 9, ds1307->regs);
+ if (ret != 9) {
dev_err(dev, "%s error %d\n", "alarm read", ret);
return -EIO;
}
@@ -353,7 +338,7 @@ static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t)
return 0;
}
-static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
@@ -371,13 +356,9 @@ static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t)
t->enabled, t->pending);
/* read current status of both alarms and the chip */
- ds1307->reg_addr = DS1339_REG_ALARM1_SECS;
- ds1307->msg[1].flags = I2C_M_RD;
- ds1307->msg[1].len = 9;
-
- ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
- ds1307->msg, 2);
- if (ret != 2) {
+ ret = i2c_smbus_read_i2c_block_data(client,
+ DS1339_REG_ALARM1_SECS, 9, buf);
+ if (ret != 9) {
dev_err(dev, "%s error %d\n", "alarm write", ret);
return -EIO;
}
@@ -392,7 +373,6 @@ static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t)
ds1307->regs[6], control, status);
/* set ALARM1, using 24 hour and day-of-month modes */
- *buf++ = DS1339_REG_ALARM1_SECS; /* first register addr */
buf[0] = bin2bcd(t->time.tm_sec);
buf[1] = bin2bcd(t->time.tm_min);
buf[2] = bin2bcd(t->time.tm_hour);
@@ -411,14 +391,11 @@ static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t)
}
buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I);
- ds1307->msg[1].flags = 0;
- ds1307->msg[1].len = 10;
-
- ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
- &ds1307->msg[1], 1);
- if (ret != 1) {
+ ret = i2c_smbus_write_i2c_block_data(client,
+ DS1339_REG_ALARM1_SECS, 9, buf);
+ if (ret < 0) {
dev_err(dev, "can't set alarm time\n");
- return -EIO;
+ return ret;
}
return 0;
@@ -475,8 +452,8 @@ static int ds1307_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
static const struct rtc_class_ops ds13xx_rtc_ops = {
.read_time = ds1307_get_time,
.set_time = ds1307_set_time,
- .read_alarm = ds1307_read_alarm,
- .set_alarm = ds1307_set_alarm,
+ .read_alarm = ds1337_read_alarm,
+ .set_alarm = ds1337_set_alarm,
.ioctl = ds1307_ioctl,
};
@@ -490,7 +467,6 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
{
struct i2c_client *client;
struct ds1307 *ds1307;
- struct i2c_msg msg[2];
int result;
client = kobj_to_i2c_client(kobj);
@@ -503,24 +479,10 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
if (unlikely(!count))
return count;
- msg[0].addr = client->addr;
- msg[0].flags = 0;
- msg[0].len = 1;
- msg[0].buf = buf;
-
- buf[0] = 8 + off;
-
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].len = count;
- msg[1].buf = buf;
-
- result = i2c_transfer(to_i2c_adapter(client->dev.parent), msg, 2);
- if (result != 2) {
+ result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf);
+ if (result < 0)
dev_err(&client->dev, "%s error %d\n", "nvram read", result);
- return -EIO;
- }
- return count;
+ return result;
}
static ssize_t
@@ -528,8 +490,7 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct i2c_client *client;
- u8 buffer[NVRAM_SIZE + 1];
- int ret;
+ int result;
client = kobj_to_i2c_client(kobj);
@@ -540,11 +501,12 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
if (unlikely(!count))
return count;
- buffer[0] = 8 + off;
- memcpy(buffer + 1, buf, count);
-
- ret = i2c_master_send(client, buffer, count + 1);
- return (ret < 0) ? ret : (ret - 1);
+ result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf);
+ if (result < 0) {
+ dev_err(&client->dev, "%s error %d\n", "nvram write", result);
+ return result;
+ }
+ return count;
}
static struct bin_attribute nvram = {
@@ -571,9 +533,11 @@ static int __devinit ds1307_probe(struct i2c_client *client,
const struct chip_desc *chip = &chips[id->driver_data];
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
int want_irq = false;
+ unsigned char *buf;
if (!i2c_check_functionality(adapter,
- I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK))
return -EIO;
if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL)))
@@ -581,18 +545,8 @@ static int __devinit ds1307_probe(struct i2c_client *client,
ds1307->client = client;
i2c_set_clientdata(client, ds1307);
-
- ds1307->msg[0].addr = client->addr;
- ds1307->msg[0].flags = 0;
- ds1307->msg[0].len = 1;
- ds1307->msg[0].buf = &ds1307->reg_addr;
-
- ds1307->msg[1].addr = client->addr;
- ds1307->msg[1].flags = I2C_M_RD;
- ds1307->msg[1].len = sizeof(ds1307->regs);
- ds1307->msg[1].buf = ds1307->regs;
-
ds1307->type = id->driver_data;
+ buf = ds1307->regs;
switch (ds1307->type) {
case ds_1337:
@@ -602,21 +556,15 @@ static int __devinit ds1307_probe(struct i2c_client *client,
INIT_WORK(&ds1307->work, ds1307_work);
want_irq = true;
}
-
- ds1307->reg_addr = DS1337_REG_CONTROL;
- ds1307->msg[1].len = 2;
-
/* get registers that the "rtc" read below won't read... */
- tmp = i2c_transfer(adapter, ds1307->msg, 2);
+ tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
+ DS1337_REG_CONTROL, 2, buf);
if (tmp != 2) {
pr_debug("read error %d\n", tmp);
err = -EIO;
goto exit_free;
}
- ds1307->reg_addr = 0;
- ds1307->msg[1].len = sizeof(ds1307->regs);
-
/* oscillator off? turn it on, so clock can tick. */
if (ds1307->regs[0] & DS1337_BIT_nEOSC)
ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
@@ -647,9 +595,8 @@ static int __devinit ds1307_probe(struct i2c_client *client,
read_rtc:
/* read RTC registers */
-
- tmp = i2c_transfer(adapter, ds1307->msg, 2);
- if (tmp != 2) {
+ tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf);
+ if (tmp != 8) {
pr_debug("read error %d\n", tmp);
err = -EIO;
goto exit_free;
@@ -707,22 +654,6 @@ read_rtc:
break;
}
- tmp = ds1307->regs[DS1307_REG_SECS];
- tmp = bcd2bin(tmp & 0x7f);
- if (tmp > 60)
- goto exit_bad;
- tmp = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f);
- if (tmp > 60)
- goto exit_bad;
-
- tmp = bcd2bin(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
- if (tmp == 0 || tmp > 31)
- goto exit_bad;
-
- tmp = bcd2bin(ds1307->regs[DS1307_REG_MONTH] & 0x1f);
- if (tmp == 0 || tmp > 12)
- goto exit_bad;
-
tmp = ds1307->regs[DS1307_REG_HOUR];
switch (ds1307->type) {
case ds_1340:
@@ -779,13 +710,6 @@ read_rtc:
return 0;
-exit_bad:
- dev_dbg(&client->dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
- "bogus register",
- ds1307->regs[0], ds1307->regs[1],
- ds1307->regs[2], ds1307->regs[3],
- ds1307->regs[4], ds1307->regs[5],
- ds1307->regs[6]);
exit_irq:
if (ds1307->rtc)
rtc_device_unregister(ds1307->rtc);
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index 23a07fe15a2c..0b6b7730c716 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -630,7 +630,7 @@ ds1511_rtc_init(void)
static void __exit
ds1511_rtc_exit(void)
{
- return platform_driver_unregister(&ds1511_rtc_driver);
+ platform_driver_unregister(&ds1511_rtc_driver);
}
module_init(ds1511_rtc_init);
diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c
index 346d633655e7..c6bfa6fe1a2a 100644
--- a/drivers/rtc/rtc-parisc.c
+++ b/drivers/rtc/rtc-parisc.c
@@ -34,7 +34,8 @@ static int parisc_get_time(struct device *dev, struct rtc_time *tm)
static int parisc_set_time(struct device *dev, struct rtc_time *tm)
{
struct parisc_rtc *p = dev_get_drvdata(dev);
- unsigned long flags, ret;
+ unsigned long flags;
+ int ret;
spin_lock_irqsave(&p->lock, flags);
ret = set_rtc_time(tm);
diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c
new file mode 100644
index 000000000000..f4dd87e29075
--- /dev/null
+++ b/drivers/rtc/rtc-pcf50633.c
@@ -0,0 +1,344 @@
+/* NXP PCF50633 RTC Driver
+ *
+ * (C) 2006-2008 by Openmoko, Inc.
+ * Author: Balaji Rao <balajirrao@openmoko.org>
+ * All rights reserved.
+ *
+ * Broken down from monstrous PCF50633 driver mainly by
+ * Harald Welte, Andy Green and Werner Almesberger
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/err.h>
+
+#include <linux/mfd/pcf50633/core.h>
+
+#define PCF50633_REG_RTCSC 0x59 /* Second */
+#define PCF50633_REG_RTCMN 0x5a /* Minute */
+#define PCF50633_REG_RTCHR 0x5b /* Hour */
+#define PCF50633_REG_RTCWD 0x5c /* Weekday */
+#define PCF50633_REG_RTCDT 0x5d /* Day */
+#define PCF50633_REG_RTCMT 0x5e /* Month */
+#define PCF50633_REG_RTCYR 0x5f /* Year */
+#define PCF50633_REG_RTCSCA 0x60 /* Alarm Second */
+#define PCF50633_REG_RTCMNA 0x61 /* Alarm Minute */
+#define PCF50633_REG_RTCHRA 0x62 /* Alarm Hour */
+#define PCF50633_REG_RTCWDA 0x63 /* Alarm Weekday */
+#define PCF50633_REG_RTCDTA 0x64 /* Alarm Day */
+#define PCF50633_REG_RTCMTA 0x65 /* Alarm Month */
+#define PCF50633_REG_RTCYRA 0x66 /* Alarm Year */
+
+enum pcf50633_time_indexes {
+ PCF50633_TI_SEC,
+ PCF50633_TI_MIN,
+ PCF50633_TI_HOUR,
+ PCF50633_TI_WKDAY,
+ PCF50633_TI_DAY,
+ PCF50633_TI_MONTH,
+ PCF50633_TI_YEAR,
+ PCF50633_TI_EXTENT /* always last */
+};
+
+struct pcf50633_time {
+ u_int8_t time[PCF50633_TI_EXTENT];
+};
+
+struct pcf50633_rtc {
+ int alarm_enabled;
+ int second_enabled;
+
+ struct pcf50633 *pcf;
+ struct rtc_device *rtc_dev;
+};
+
+static void pcf2rtc_time(struct rtc_time *rtc, struct pcf50633_time *pcf)
+{
+ rtc->tm_sec = bcd2bin(pcf->time[PCF50633_TI_SEC]);
+ rtc->tm_min = bcd2bin(pcf->time[PCF50633_TI_MIN]);
+ rtc->tm_hour = bcd2bin(pcf->time[PCF50633_TI_HOUR]);
+ rtc->tm_wday = bcd2bin(pcf->time[PCF50633_TI_WKDAY]);
+ rtc->tm_mday = bcd2bin(pcf->time[PCF50633_TI_DAY]);
+ rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]);
+ rtc->tm_year = bcd2bin(pcf->time[PCF50633_TI_YEAR]) + 100;
+}
+
+static void rtc2pcf_time(struct pcf50633_time *pcf, struct rtc_time *rtc)
+{
+ pcf->time[PCF50633_TI_SEC] = bin2bcd(rtc->tm_sec);
+ pcf->time[PCF50633_TI_MIN] = bin2bcd(rtc->tm_min);
+ pcf->time[PCF50633_TI_HOUR] = bin2bcd(rtc->tm_hour);
+ pcf->time[PCF50633_TI_WKDAY] = bin2bcd(rtc->tm_wday);
+ pcf->time[PCF50633_TI_DAY] = bin2bcd(rtc->tm_mday);
+ pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon);
+ pcf->time[PCF50633_TI_YEAR] = bin2bcd(rtc->tm_year % 100);
+}
+
+static int
+pcf50633_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct pcf50633_rtc *rtc = dev_get_drvdata(dev);
+ int err;
+
+ if (enabled)
+ err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
+ else
+ err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
+
+ if (err < 0)
+ return err;
+
+ rtc->alarm_enabled = enabled;
+
+ return 0;
+}
+
+static int
+pcf50633_rtc_update_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct pcf50633_rtc *rtc = dev_get_drvdata(dev);
+ int err;
+
+ if (enabled)
+ err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND);
+ else
+ err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND);
+
+ if (err < 0)
+ return err;
+
+ rtc->second_enabled = enabled;
+
+ return 0;
+}
+
+static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pcf50633_rtc *rtc;
+ struct pcf50633_time pcf_tm;
+ int ret;
+
+ rtc = dev_get_drvdata(dev);
+
+ ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSC,
+ PCF50633_TI_EXTENT,
+ &pcf_tm.time[0]);
+ if (ret != PCF50633_TI_EXTENT) {
+ dev_err(dev, "Failed to read time\n");
+ return -EIO;
+ }
+
+ dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n",
+ pcf_tm.time[PCF50633_TI_DAY],
+ pcf_tm.time[PCF50633_TI_MONTH],
+ pcf_tm.time[PCF50633_TI_YEAR],
+ pcf_tm.time[PCF50633_TI_HOUR],
+ pcf_tm.time[PCF50633_TI_MIN],
+ pcf_tm.time[PCF50633_TI_SEC]);
+
+ pcf2rtc_time(tm, &pcf_tm);
+
+ dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n",
+ tm->tm_mday, tm->tm_mon, tm->tm_year,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return rtc_valid_tm(tm);
+}
+
+static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pcf50633_rtc *rtc;
+ struct pcf50633_time pcf_tm;
+ int second_masked, alarm_masked, ret = 0;
+
+ rtc = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n",
+ tm->tm_mday, tm->tm_mon, tm->tm_year,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ rtc2pcf_time(&pcf_tm, tm);
+
+ dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n",
+ pcf_tm.time[PCF50633_TI_DAY],
+ pcf_tm.time[PCF50633_TI_MONTH],
+ pcf_tm.time[PCF50633_TI_YEAR],
+ pcf_tm.time[PCF50633_TI_HOUR],
+ pcf_tm.time[PCF50633_TI_MIN],
+ pcf_tm.time[PCF50633_TI_SEC]);
+
+
+ second_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_SECOND);
+ alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM);
+
+ if (!second_masked)
+ pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND);
+ if (!alarm_masked)
+ pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
+
+ /* Returns 0 on success */
+ ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSC,
+ PCF50633_TI_EXTENT,
+ &pcf_tm.time[0]);
+
+ if (!second_masked)
+ pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND);
+ if (!alarm_masked)
+ pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
+
+ return ret;
+}
+
+static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct pcf50633_rtc *rtc;
+ struct pcf50633_time pcf_tm;
+ int ret = 0;
+
+ rtc = dev_get_drvdata(dev);
+
+ alrm->enabled = rtc->alarm_enabled;
+
+ ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA,
+ PCF50633_TI_EXTENT, &pcf_tm.time[0]);
+ if (ret != PCF50633_TI_EXTENT) {
+ dev_err(dev, "Failed to read time\n");
+ return -EIO;
+ }
+
+ pcf2rtc_time(&alrm->time, &pcf_tm);
+
+ return rtc_valid_tm(&alrm->time);
+}
+
+static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct pcf50633_rtc *rtc;
+ struct pcf50633_time pcf_tm;
+ int alarm_masked, ret = 0;
+
+ rtc = dev_get_drvdata(dev);
+
+ rtc2pcf_time(&pcf_tm, &alrm->time);
+
+ /* do like mktime does and ignore tm_wday */
+ pcf_tm.time[PCF50633_TI_WKDAY] = 7;
+
+ alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM);
+
+ /* disable alarm interrupt */
+ if (!alarm_masked)
+ pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
+
+ /* Returns 0 on success */
+ ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA,
+ PCF50633_TI_EXTENT, &pcf_tm.time[0]);
+
+ if (!alarm_masked)
+ pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
+
+ return ret;
+}
+
+static struct rtc_class_ops pcf50633_rtc_ops = {
+ .read_time = pcf50633_rtc_read_time,
+ .set_time = pcf50633_rtc_set_time,
+ .read_alarm = pcf50633_rtc_read_alarm,
+ .set_alarm = pcf50633_rtc_set_alarm,
+ .alarm_irq_enable = pcf50633_rtc_alarm_irq_enable,
+ .update_irq_enable = pcf50633_rtc_update_irq_enable,
+};
+
+static void pcf50633_rtc_irq(int irq, void *data)
+{
+ struct pcf50633_rtc *rtc = data;
+
+ switch (irq) {
+ case PCF50633_IRQ_ALARM:
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
+ break;
+ case PCF50633_IRQ_SECOND:
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
+ break;
+ }
+}
+
+static int __devinit pcf50633_rtc_probe(struct platform_device *pdev)
+{
+ struct pcf50633_subdev_pdata *pdata;
+ struct pcf50633_rtc *rtc;
+
+
+ rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ pdata = pdev->dev.platform_data;
+ rtc->pcf = pdata->pcf;
+ platform_set_drvdata(pdev, rtc);
+ rtc->rtc_dev = rtc_device_register("pcf50633-rtc", &pdev->dev,
+ &pcf50633_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rtc->rtc_dev)) {
+ kfree(rtc);
+ return PTR_ERR(rtc->rtc_dev);
+ }
+
+ pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM,
+ pcf50633_rtc_irq, rtc);
+ pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_SECOND,
+ pcf50633_rtc_irq, rtc);
+
+ return 0;
+}
+
+static int __devexit pcf50633_rtc_remove(struct platform_device *pdev)
+{
+ struct pcf50633_rtc *rtc;
+
+ rtc = platform_get_drvdata(pdev);
+
+ pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM);
+ pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_SECOND);
+
+ rtc_device_unregister(rtc->rtc_dev);
+ kfree(rtc);
+
+ return 0;
+}
+
+static struct platform_driver pcf50633_rtc_driver = {
+ .driver = {
+ .name = "pcf50633-rtc",
+ },
+ .probe = pcf50633_rtc_probe,
+ .remove = __devexit_p(pcf50633_rtc_remove),
+};
+
+static int __init pcf50633_rtc_init(void)
+{
+ return platform_driver_register(&pcf50633_rtc_driver);
+}
+module_init(pcf50633_rtc_init);
+
+static void __exit pcf50633_rtc_exit(void)
+{
+ platform_driver_unregister(&pcf50633_rtc_driver);
+}
+module_exit(pcf50633_rtc_exit);
+
+MODULE_DESCRIPTION("PCF50633 RTC driver");
+MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c
index cc7eb8767b82..bd56a033bfd0 100644
--- a/drivers/rtc/rtc-pxa.c
+++ b/drivers/rtc/rtc-pxa.c
@@ -27,6 +27,8 @@
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <mach/hardware.h>
+
#define TIMER_FREQ CLOCK_TICK_RATE
#define RTC_DEF_DIVIDER (32768 - 1)
#define RTC_DEF_TRIM 0
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index dc0b6224ad9b..7d1547b0070e 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -399,7 +399,7 @@ static __init int stk17ta8_init(void)
static __exit void stk17ta8_exit(void)
{
- return platform_driver_unregister(&stk17ta8_rtc_driver);
+ platform_driver_unregister(&stk17ta8_rtc_driver);
}
module_init(stk17ta8_init);
diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl4030.c
index 8ce5f74ee45b..ad35f76c46b7 100644
--- a/drivers/rtc/rtc-twl4030.c
+++ b/drivers/rtc/rtc-twl4030.c
@@ -120,7 +120,7 @@ static int twl4030_rtc_write_u8(u8 data, u8 reg)
static unsigned char rtc_irq_bits;
/*
- * Enable timer and/or alarm interrupts.
+ * Enable 1/second update and/or alarm interrupts.
*/
static int set_rtc_irq_bit(unsigned char bit)
{
@@ -128,6 +128,7 @@ static int set_rtc_irq_bit(unsigned char bit)
int ret;
val = rtc_irq_bits | bit;
+ val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
if (ret == 0)
rtc_irq_bits = val;
@@ -136,7 +137,7 @@ static int set_rtc_irq_bit(unsigned char bit)
}
/*
- * Disable timer and/or alarm interrupts.
+ * Disable update and/or alarm interrupts.
*/
static int mask_rtc_irq_bit(unsigned char bit)
{
@@ -151,7 +152,7 @@ static int mask_rtc_irq_bit(unsigned char bit)
return ret;
}
-static inline int twl4030_rtc_alarm_irq_set_state(int enabled)
+static int twl4030_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
{
int ret;
@@ -163,7 +164,7 @@ static inline int twl4030_rtc_alarm_irq_set_state(int enabled)
return ret;
}
-static inline int twl4030_rtc_irq_set_state(int enabled)
+static int twl4030_rtc_update_irq_enable(struct device *dev, unsigned enabled)
{
int ret;
@@ -292,7 +293,7 @@ static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
unsigned char alarm_data[ALL_TIME_REGS + 1];
int ret;
- ret = twl4030_rtc_alarm_irq_set_state(0);
+ ret = twl4030_rtc_alarm_irq_enable(dev, 0);
if (ret)
goto out;
@@ -312,35 +313,11 @@ static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
}
if (alm->enabled)
- ret = twl4030_rtc_alarm_irq_set_state(1);
+ ret = twl4030_rtc_alarm_irq_enable(dev, 1);
out:
return ret;
}
-#ifdef CONFIG_RTC_INTF_DEV
-
-static int twl4030_rtc_ioctl(struct device *dev, unsigned int cmd,
- unsigned long arg)
-{
- switch (cmd) {
- case RTC_AIE_OFF:
- return twl4030_rtc_alarm_irq_set_state(0);
- case RTC_AIE_ON:
- return twl4030_rtc_alarm_irq_set_state(1);
- case RTC_UIE_OFF:
- return twl4030_rtc_irq_set_state(0);
- case RTC_UIE_ON:
- return twl4030_rtc_irq_set_state(1);
-
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-#else
-#define twl4030_rtc_ioctl NULL
-#endif
-
static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc)
{
unsigned long events = 0;
@@ -400,11 +377,12 @@ out:
}
static struct rtc_class_ops twl4030_rtc_ops = {
- .ioctl = twl4030_rtc_ioctl,
.read_time = twl4030_rtc_read_time,
.set_time = twl4030_rtc_set_time,
.read_alarm = twl4030_rtc_read_alarm,
.set_alarm = twl4030_rtc_set_alarm,
+ .alarm_irq_enable = twl4030_rtc_alarm_irq_enable,
+ .update_irq_enable = twl4030_rtc_update_irq_enable,
};
/*----------------------------------------------------------------------*/
@@ -422,7 +400,7 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev)
rtc = rtc_device_register(pdev->name,
&pdev->dev, &twl4030_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
- ret = -EINVAL;
+ ret = PTR_ERR(rtc);
dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
PTR_ERR(rtc));
goto out0;
@@ -432,7 +410,6 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rtc);
ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
-
if (ret < 0)
goto out1;
@@ -475,7 +452,6 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev)
return ret;
-
out2:
free_irq(irq, rtc);
out1:
@@ -506,8 +482,9 @@ static int __devexit twl4030_rtc_remove(struct platform_device *pdev)
static void twl4030_rtc_shutdown(struct platform_device *pdev)
{
- mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M |
- BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+ /* mask timer interrupts, but leave alarm interrupts on to enable
+ power-on when alarm is triggered */
+ mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
}
#ifdef CONFIG_PM
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 570ae59c1d5e..bd5914994142 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -336,6 +336,9 @@ static int
dasd_state_ready_to_online(struct dasd_device * device)
{
int rc;
+ struct gendisk *disk;
+ struct disk_part_iter piter;
+ struct hd_struct *part;
if (device->discipline->ready_to_online) {
rc = device->discipline->ready_to_online(device);
@@ -343,8 +346,14 @@ dasd_state_ready_to_online(struct dasd_device * device)
return rc;
}
device->state = DASD_STATE_ONLINE;
- if (device->block)
+ if (device->block) {
dasd_schedule_block_bh(device->block);
+ disk = device->block->bdev->bd_disk;
+ disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
+ while ((part = disk_part_iter_next(&piter)))
+ kobject_uevent(&part_to_dev(part)->kobj, KOBJ_CHANGE);
+ disk_part_iter_exit(&piter);
+ }
return 0;
}
@@ -354,6 +363,9 @@ dasd_state_ready_to_online(struct dasd_device * device)
static int dasd_state_online_to_ready(struct dasd_device *device)
{
int rc;
+ struct gendisk *disk;
+ struct disk_part_iter piter;
+ struct hd_struct *part;
if (device->discipline->online_to_ready) {
rc = device->discipline->online_to_ready(device);
@@ -361,6 +373,13 @@ static int dasd_state_online_to_ready(struct dasd_device *device)
return rc;
}
device->state = DASD_STATE_READY;
+ if (device->block) {
+ disk = device->block->bdev->bd_disk;
+ disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
+ while ((part = disk_part_iter_next(&piter)))
+ kobject_uevent(&part_to_dev(part)->kobj, KOBJ_CHANGE);
+ disk_part_iter_exit(&piter);
+ }
return 0;
}
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index b8f9c00633f3..d82aad5224f0 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -2621,7 +2621,7 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
}
}
- /* double-check if current erp/cqr was successfull */
+ /* double-check if current erp/cqr was successful */
if ((cqr->irb.scsw.cmd.cstat == 0x00) &&
(cqr->irb.scsw.cmd.dstat ==
(DEV_STAT_CHN_END | DEV_STAT_DEV_END))) {
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 2ef25731d197..300e28a531f8 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -206,6 +206,8 @@ dasd_feature_list(char *str, char **endp)
features |= DASD_FEATURE_USEDIAG;
else if (len == 6 && !strncmp(str, "erplog", 6))
features |= DASD_FEATURE_ERPLOG;
+ else if (len == 8 && !strncmp(str, "failfast", 8))
+ features |= DASD_FEATURE_FAILFAST;
else {
MESSAGE(KERN_WARNING,
"unsupported feature: %*s, "
@@ -667,6 +669,51 @@ dasd_device_from_cdev(struct ccw_device *cdev)
*/
/*
+ * failfast controls the behaviour, if no path is available
+ */
+static ssize_t dasd_ff_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dasd_devmap *devmap;
+ int ff_flag;
+
+ devmap = dasd_find_busid(dev->bus_id);
+ if (!IS_ERR(devmap))
+ ff_flag = (devmap->features & DASD_FEATURE_FAILFAST) != 0;
+ else
+ ff_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_FAILFAST) != 0;
+ return snprintf(buf, PAGE_SIZE, ff_flag ? "1\n" : "0\n");
+}
+
+static ssize_t dasd_ff_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dasd_devmap *devmap;
+ int val;
+ char *endp;
+
+ devmap = dasd_devmap_from_cdev(to_ccwdev(dev));
+ if (IS_ERR(devmap))
+ return PTR_ERR(devmap);
+
+ val = simple_strtoul(buf, &endp, 0);
+ if (((endp + 1) < (buf + count)) || (val > 1))
+ return -EINVAL;
+
+ spin_lock(&dasd_devmap_lock);
+ if (val)
+ devmap->features |= DASD_FEATURE_FAILFAST;
+ else
+ devmap->features &= ~DASD_FEATURE_FAILFAST;
+ if (devmap->device)
+ devmap->device->features = devmap->features;
+ spin_unlock(&dasd_devmap_lock);
+ return count;
+}
+
+static DEVICE_ATTR(failfast, 0644, dasd_ff_show, dasd_ff_store);
+
+/*
* readonly controls the readonly status of a dasd
*/
static ssize_t
@@ -1020,6 +1067,7 @@ static struct attribute * dasd_attrs[] = {
&dev_attr_use_diag.attr,
&dev_attr_eer_enabled.attr,
&dev_attr_erplog.attr,
+ &dev_attr_failfast.attr,
NULL,
};
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 7844461a995b..ef2a56952054 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -544,7 +544,8 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
}
cqr->retries = DIAG_MAX_RETRIES;
cqr->buildclk = get_clock();
- if (blk_noretry_request(req))
+ if (blk_noretry_request(req) ||
+ block->base->features & DASD_FEATURE_FAILFAST)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->startdev = memdev;
cqr->memdev = memdev;
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index bd2c52e20762..bdb87998f364 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1700,7 +1700,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
recid++;
}
}
- if (blk_noretry_request(req))
+ if (blk_noretry_request(req) ||
+ block->base->features & DASD_FEATURE_FAILFAST)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->startdev = startdev;
cqr->memdev = startdev;
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index 892e2878d61b..f8e05ce98621 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -535,8 +535,8 @@ static int dasd_eer_open(struct inode *inp, struct file *filp)
eerb->buffer_page_count > INT_MAX / PAGE_SIZE) {
kfree(eerb);
MESSAGE(KERN_WARNING, "can't open device since module "
- "parameter eer_pages is smaller then 1 or"
- " bigger then %d", (int)(INT_MAX / PAGE_SIZE));
+ "parameter eer_pages is smaller than 1 or"
+ " bigger than %d", (int)(INT_MAX / PAGE_SIZE));
unlock_kernel();
return -EINVAL;
}
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index 7d442aeff3d1..f1d176021694 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -355,7 +355,8 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
recid++;
}
}
- if (blk_noretry_request(req))
+ if (blk_noretry_request(req) ||
+ block->base->features & DASD_FEATURE_FAILFAST)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->startdev = memdev;
cqr->memdev = memdev;
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 05a14536c369..4a39084d9c95 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -199,7 +199,7 @@ struct dasd_ccw_req {
#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 */
+#define DASD_CQR_SUCCESS 0x85 /* request was successful */
/* per dasd_ccw_req flags */
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index 643033890e34..0769ced52dbd 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -100,7 +100,7 @@ comment "S/390 tape interface support"
config S390_TAPE_BLOCK
bool "Support for tape block devices"
- depends on S390_TAPE
+ depends on S390_TAPE && BLOCK
help
Select this option if you want to access your channel-attached tape
devices using the block device interface. This interface is similar
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 4005c44a404c..71605a179d65 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -801,7 +801,7 @@ tape_3590_done(struct tape_device *device, struct tape_request *request)
static inline int
tape_3590_erp_succeded(struct tape_device *device, struct tape_request *request)
{
- DBF_EVENT(3, "Error Recovery successfull for %s\n",
+ DBF_EVENT(3, "Error Recovery successful for %s\n",
tape_op_verbose[request->op]);
return tape_3590_done(device, request);
}
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index aabbeb909cc6..d8a2289fcb69 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -427,7 +427,7 @@ static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv)
buffer = priv->buffer + sizeof(int);
}
/*
- * If the record is bigger then our buffer, we receive only
+ * If the record is bigger than our buffer, we receive only
* a part of it. We can get the rest later.
*/
if (iucv_data_count > NET_BUFFER_SIZE)
@@ -437,7 +437,7 @@ static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv)
0, buffer, iucv_data_count,
&priv->residual_length);
spin_unlock_bh(&priv->priv_lock);
- /* An rc of 5 indicates that the record was bigger then
+ /* An rc of 5 indicates that the record was bigger than
* the buffer, which is OK for us. A 9 indicates that the
* record was purged befor we could receive it.
*/
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 06b71823f399..659f8a791656 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -379,7 +379,7 @@ int cio_commit_config(struct subchannel *sch)
if (ccode < 0) /* -EIO if msch gets a program check. */
return ccode;
switch (ccode) {
- case 0: /* successfull */
+ case 0: /* successful */
if (stsch(sch->schid, &schib) ||
!css_sch_is_valid(&schib))
return -ENODEV;
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index f8a3b6967f69..da7afb04e71f 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -169,6 +169,8 @@ static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
q->nr);
debugfs_queues[i] = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
debugfs_root, q, &debugfs_fops);
+ if (IS_ERR(debugfs_queues[i]))
+ debugfs_queues[i] = NULL;
}
void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 744f928a59ea..10cb0f8726e5 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -114,7 +114,7 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
* @count: count of buffers to examine
* @auto_ack: automatically acknowledge buffers
*
- * Returns the number of successfull extracted equal buffer states.
+ * Returns the number of successfully extracted equal buffer states.
* Stops processing if a state is different from the last buffers state.
*/
static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 591a2b3ae4cb..07ab8a5c1c46 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -916,6 +916,21 @@ static struct ethtool_ops qeth_l2_osn_ops = {
.get_drvinfo = qeth_core_get_drvinfo,
};
+static const struct net_device_ops qeth_l2_netdev_ops = {
+ .ndo_open = qeth_l2_open,
+ .ndo_stop = qeth_l2_stop,
+ .ndo_get_stats = qeth_get_stats,
+ .ndo_start_xmit = qeth_l2_hard_start_xmit,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_multicast_list = qeth_l2_set_multicast_list,
+ .ndo_do_ioctl = qeth_l2_do_ioctl,
+ .ndo_set_mac_address = qeth_l2_set_mac_address,
+ .ndo_change_mtu = qeth_change_mtu,
+ .ndo_vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid,
+ .ndo_tx_timeout = qeth_tx_timeout,
+};
+
static int qeth_l2_setup_netdev(struct qeth_card *card)
{
switch (card->info.type) {
@@ -937,19 +952,9 @@ static int qeth_l2_setup_netdev(struct qeth_card *card)
return -ENODEV;
card->dev->ml_priv = card;
- card->dev->tx_timeout = &qeth_tx_timeout;
card->dev->watchdog_timeo = QETH_TX_TIMEOUT;
- card->dev->open = qeth_l2_open;
- card->dev->stop = qeth_l2_stop;
- card->dev->hard_start_xmit = qeth_l2_hard_start_xmit;
- card->dev->do_ioctl = qeth_l2_do_ioctl;
- card->dev->get_stats = qeth_get_stats;
- card->dev->change_mtu = qeth_change_mtu;
- card->dev->set_multicast_list = qeth_l2_set_multicast_list;
- card->dev->vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid;
- card->dev->vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid;
- card->dev->set_mac_address = qeth_l2_set_mac_address;
card->dev->mtu = card->info.initial_mtu;
+ card->dev->netdev_ops = &qeth_l2_netdev_ops;
if (card->info.type != QETH_CARD_TYPE_OSN)
SET_ETHTOOL_OPS(card->dev, &qeth_l2_ethtool_ops);
else
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 4693ee4e7b98..3d04920b9bb9 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -1829,28 +1829,6 @@ static void qeth_l3_vlan_rx_register(struct net_device *dev,
static void qeth_l3_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
{
- struct net_device *vlandev;
- struct qeth_card *card = dev->ml_priv;
- struct in_device *in_dev;
-
- if (card->info.type == QETH_CARD_TYPE_IQD)
- return;
-
- vlandev = vlan_group_get_device(card->vlangrp, vid);
- vlandev->neigh_setup = qeth_l3_neigh_setup;
-
- in_dev = in_dev_get(vlandev);
-#ifdef CONFIG_SYSCTL
- neigh_sysctl_unregister(in_dev->arp_parms);
-#endif
- neigh_parms_release(&arp_tbl, in_dev->arp_parms);
-
- in_dev->arp_parms = neigh_parms_alloc(vlandev, &arp_tbl);
-#ifdef CONFIG_SYSCTL
- neigh_sysctl_register(vlandev, in_dev->arp_parms, NET_IPV4,
- NET_IPV4_NEIGH, "ipv4", NULL, NULL);
-#endif
- in_dev_put(in_dev);
return;
}
@@ -2916,6 +2894,37 @@ qeth_l3_neigh_setup(struct net_device *dev, struct neigh_parms *np)
return 0;
}
+static const struct net_device_ops qeth_l3_netdev_ops = {
+ .ndo_open = qeth_l3_open,
+ .ndo_stop = qeth_l3_stop,
+ .ndo_get_stats = qeth_get_stats,
+ .ndo_start_xmit = qeth_l3_hard_start_xmit,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_multicast_list = qeth_l3_set_multicast_list,
+ .ndo_do_ioctl = qeth_l3_do_ioctl,
+ .ndo_change_mtu = qeth_change_mtu,
+ .ndo_vlan_rx_register = qeth_l3_vlan_rx_register,
+ .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid,
+ .ndo_tx_timeout = qeth_tx_timeout,
+};
+
+static const struct net_device_ops qeth_l3_osa_netdev_ops = {
+ .ndo_open = qeth_l3_open,
+ .ndo_stop = qeth_l3_stop,
+ .ndo_get_stats = qeth_get_stats,
+ .ndo_start_xmit = qeth_l3_hard_start_xmit,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_multicast_list = qeth_l3_set_multicast_list,
+ .ndo_do_ioctl = qeth_l3_do_ioctl,
+ .ndo_change_mtu = qeth_change_mtu,
+ .ndo_vlan_rx_register = qeth_l3_vlan_rx_register,
+ .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid,
+ .ndo_tx_timeout = qeth_tx_timeout,
+ .ndo_neigh_setup = qeth_l3_neigh_setup,
+};
+
static int qeth_l3_setup_netdev(struct qeth_card *card)
{
if (card->info.type == QETH_CARD_TYPE_OSAE) {
@@ -2926,11 +2935,12 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
#endif
if (!card->dev)
return -ENODEV;
+ card->dev->netdev_ops = &qeth_l3_netdev_ops;
} else {
card->dev = alloc_etherdev(0);
if (!card->dev)
return -ENODEV;
- card->dev->neigh_setup = qeth_l3_neigh_setup;
+ card->dev->netdev_ops = &qeth_l3_osa_netdev_ops;
/*IPv6 address autoconfiguration stuff*/
qeth_l3_get_unique_id(card);
@@ -2943,25 +2953,14 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
if (!card->dev)
return -ENODEV;
card->dev->flags |= IFF_NOARP;
+ card->dev->netdev_ops = &qeth_l3_netdev_ops;
qeth_l3_iqd_read_initial_mac(card);
} else
return -ENODEV;
- card->dev->hard_start_xmit = qeth_l3_hard_start_xmit;
card->dev->ml_priv = card;
- card->dev->tx_timeout = &qeth_tx_timeout;
card->dev->watchdog_timeo = QETH_TX_TIMEOUT;
- card->dev->open = qeth_l3_open;
- card->dev->stop = qeth_l3_stop;
- card->dev->do_ioctl = qeth_l3_do_ioctl;
- card->dev->get_stats = qeth_get_stats;
- card->dev->change_mtu = qeth_change_mtu;
- card->dev->set_multicast_list = qeth_l3_set_multicast_list;
- card->dev->vlan_rx_register = qeth_l3_vlan_rx_register;
- card->dev->vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid;
- card->dev->vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid;
card->dev->mtu = card->info.initial_mtu;
- card->dev->set_mac_address = NULL;
SET_ETHTOOL_OPS(card->dev, &qeth_l3_ethtool_ops);
card->dev->features |= NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index 2550af4ae432..4431578d8c45 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -214,7 +214,7 @@ static int __devinit d7s_probe(struct of_device *op,
writeb(regs, p->regs);
- printk(KERN_INFO PFX "7-Segment Display%s at [%s:0x%lx] %s\n",
+ printk(KERN_INFO PFX "7-Segment Display%s at [%s:0x%llx] %s\n",
op->node->full_name,
(regs & D7S_FLIP) ? " (FLIPPED)" : "",
op->resource[0].start,
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index b7322976d2b7..256c7bec7bd7 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -884,6 +884,7 @@ config SCSI_IBMVSCSI
tristate "IBM Virtual SCSI support"
depends on PPC_PSERIES || PPC_ISERIES
select SCSI_SRP_ATTRS
+ select VIOPATH if PPC_ISERIES
help
This is the IBM POWER Virtual SCSI Client
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index 9e64b21ef637..c889d8458684 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -318,7 +318,7 @@ NCR_D700_probe(struct device *dev)
return -ENOMEM;
p->dev = dev;
- snprintf(p->name, sizeof(p->name), "D700(%s)", dev->bus_id);
+ snprintf(p->name, sizeof(p->name), "D700(%s)", dev_name(dev));
if (request_irq(irq, NCR_D700_intr, IRQF_SHARED, p->name, p)) {
printk(KERN_ERR "D700: request_irq failed\n");
kfree(p);
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index 3c298c7253ee..964769f66eac 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -633,7 +633,7 @@ static int orc_device_reset(struct orc_host * host, struct scsi_cmnd *cmd, unsig
return FAILED;
}
- /* Reset device is handled by the firmare, we fill in an SCB and
+ /* Reset device is handled by the firmware, we fill in an SCB and
fire it at the controller, it does the rest */
scb->opcode = ORC_BUSDEVRST;
scb->target = target;
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index 07d572feceed..37dd47136fb1 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -169,10 +169,8 @@ int __init a2091_detect(struct scsi_host_template *tpnt)
continue;
instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
- if (instance == NULL) {
- release_mem_region(address, 256);
- continue;
- }
+ if (instance == NULL)
+ goto release;
instance->base = ZTWO_VADDR(address);
instance->irq = IRQ_AMIGA_PORTS;
instance->unique_id = z->slotaddr;
@@ -183,10 +181,18 @@ int __init a2091_detect(struct scsi_host_template *tpnt)
HDATA(instance)->fast = 0;
HDATA(instance)->dma_mode = CTRL_DMA;
wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
- request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI",
- instance);
+ if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI",
+ instance))
+ goto unregister;
DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
num_a2091++;
+ continue;
+
+unregister:
+ scsi_unregister(instance);
+ wd33c93_release();
+release:
+ release_mem_region(address, 256);
}
return num_a2091;
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 2f602720193e..7507d8bc57a1 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -2527,7 +2527,7 @@ static void asc_prt_scsi_host(struct Scsi_Host *s)
{
struct asc_board *boardp = shost_priv(s);
- printk("Scsi_Host at addr 0x%p, device %s\n", s, boardp->dev->bus_id);
+ printk("Scsi_Host at addr 0x%p, device %s\n", s, dev_name(boardp->dev));
printk(" host_busy %u, host_no %d, last_reset %d,\n",
s->host_busy, s->host_no, (unsigned)s->last_reset);
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
index d4640ef6d44f..78eb86fc6276 100644
--- a/drivers/scsi/aic94xx/aic94xx_tmf.c
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -189,7 +189,7 @@ int asd_I_T_nexus_reset(struct domain_device *dev)
asd_clear_nexus_I_T(dev, NEXUS_PHASE_PRE);
/* send a hard reset */
ASD_DPRINTK("sending %s reset to %s\n",
- reset_type ? "hard" : "soft", phy->dev.bus_id);
+ reset_type ? "hard" : "soft", dev_name(&phy->dev));
res = sas_phy_reset(phy, reset_type);
if (res == TMF_RESP_FUNC_COMPLETE) {
/* wait for the maximum settle time */
diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.c b/drivers/scsi/cxgb3i/cxgb3i_ddp.c
index 1a41f04264f7..08f3a09d9233 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_ddp.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.c
@@ -11,6 +11,7 @@
*/
#include <linux/skbuff.h>
+#include <linux/scatterlist.h>
/* from cxgb3 LLD */
#include "common.h"
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index ca7363752401..5d1bf7e3d245 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -329,12 +329,16 @@ int __init gvp11_detect(struct scsi_host_template *tpnt)
(epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
: WD33C93_FS_12_15);
- request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED, "GVP11 SCSI",
- instance);
+ if (request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED, "GVP11 SCSI",
+ instance))
+ goto unregister;
DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
num_gvp11++;
continue;
+unregister:
+ scsi_unregister(instance);
+ wd33c93_release();
release:
release_mem_region(address, 256);
}
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 3fdbb13e80a8..aa670a1d1513 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -388,8 +388,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost->dma_boundary = 0xffffffff;
device_initialize(&shost->shost_gendev);
- snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d",
- shost->host_no);
+ dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
#ifndef CONFIG_SYSFS_DEPRECATED
shost->shost_gendev.bus = &scsi_bus_type;
#endif
@@ -398,8 +397,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
device_initialize(&shost->shost_dev);
shost->shost_dev.parent = &shost->shost_gendev;
shost->shost_dev.class = &shost_class;
- snprintf(shost->shost_dev.bus_id, BUS_ID_SIZE, "host%d",
- shost->host_no);
+ dev_set_name(&shost->shost_dev, "host%d", shost->host_no);
shost->shost_dev.groups = scsi_sysfs_shost_attr_groups;
shost->ehandler = kthread_run(scsi_error_handler, shost,
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 44f202f33101..91ef669d98f6 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -101,7 +101,7 @@ static const struct {
{ IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_ESTABLISH, DID_ERROR, 1, 1, "unable to establish" },
{ IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_FAULT, DID_OK, 1, 0, "transport fault" },
{ IBMVFC_FABRIC_MAPPED, IBMVFC_CMD_TIMEOUT, DID_TIME_OUT, 1, 1, "command timeout" },
- { IBMVFC_FABRIC_MAPPED, IBMVFC_ENETDOWN, DID_NO_CONNECT, 1, 1, "network down" },
+ { IBMVFC_FABRIC_MAPPED, IBMVFC_ENETDOWN, DID_TRANSPORT_DISRUPTED, 1, 1, "network down" },
{ IBMVFC_FABRIC_MAPPED, IBMVFC_HW_FAILURE, DID_ERROR, 1, 1, "hardware failure" },
{ IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DOWN_ERR, DID_REQUEUE, 0, 0, "link down" },
{ IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DEAD_ERR, DID_ERROR, 0, 0, "link dead" },
@@ -115,11 +115,11 @@ static const struct {
{ IBMVFC_VIOS_FAILURE, IBMVFC_CRQ_FAILURE, DID_REQUEUE, 1, 1, "CRQ failure" },
{ IBMVFC_VIOS_FAILURE, IBMVFC_SW_FAILURE, DID_ERROR, 0, 1, "software failure" },
- { IBMVFC_VIOS_FAILURE, IBMVFC_INVALID_PARAMETER, DID_ABORT, 0, 1, "invalid parameter" },
- { IBMVFC_VIOS_FAILURE, IBMVFC_MISSING_PARAMETER, DID_ABORT, 0, 1, "missing parameter" },
+ { IBMVFC_VIOS_FAILURE, IBMVFC_INVALID_PARAMETER, DID_ERROR, 0, 1, "invalid parameter" },
+ { IBMVFC_VIOS_FAILURE, IBMVFC_MISSING_PARAMETER, DID_ERROR, 0, 1, "missing parameter" },
{ IBMVFC_VIOS_FAILURE, IBMVFC_HOST_IO_BUS, DID_ERROR, 1, 1, "host I/O bus failure" },
- { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ABORT, 0, 1, "transaction cancelled" },
- { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ABORT, 0, 1, "transaction cancelled implicit" },
+ { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ERROR, 0, 1, "transaction cancelled" },
+ { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ERROR, 0, 1, "transaction cancelled implicit" },
{ IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" },
{ IBMVFC_VIOS_FAILURE, IBMVFC_PLOGI_REQUIRED, DID_ERROR, 0, 1, "port login required" },
{ IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" },
@@ -933,7 +933,7 @@ static void ibmvfc_get_host_speed(struct Scsi_Host *shost)
fc_host_speed(shost) = FC_PORTSPEED_16GBIT;
break;
default:
- ibmvfc_log(vhost, 3, "Unknown port speed: %ld Gbit\n",
+ ibmvfc_log(vhost, 3, "Unknown port speed: %lld Gbit\n",
vhost->login_buf->resp.link_speed / 100);
fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
break;
@@ -1145,10 +1145,10 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
login_info->async.len = vhost->async_crq.size * sizeof(*vhost->async_crq.msgs);
strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME);
strncpy(login_info->device_name,
- vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME);
+ dev_name(&vhost->host->shost_gendev), IBMVFC_MAX_NAME);
location = of_get_property(of_node, "ibm,loc-code", NULL);
- location = location ? location : vhost->dev->bus_id;
+ location = location ? location : dev_name(vhost->dev);
strncpy(login_info->drc_name, location, IBMVFC_MAX_NAME);
}
@@ -2149,8 +2149,8 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
{
const char *desc = ibmvfc_get_ae_desc(crq->event);
- ibmvfc_log(vhost, 3, "%s event received. scsi_id: %lx, wwpn: %lx,"
- " node_name: %lx\n", desc, crq->scsi_id, crq->wwpn, crq->node_name);
+ ibmvfc_log(vhost, 3, "%s event received. scsi_id: %llx, wwpn: %llx,"
+ " node_name: %llx\n", desc, crq->scsi_id, crq->wwpn, crq->node_name);
switch (crq->event) {
case IBMVFC_AE_LINK_UP:
@@ -2184,7 +2184,7 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
ibmvfc_link_down(vhost, IBMVFC_HALTED);
break;
default:
- dev_err(vhost->dev, "Unknown async event received: %ld\n", crq->event);
+ dev_err(vhost->dev, "Unknown async event received: %lld\n", crq->event);
break;
};
}
@@ -2261,13 +2261,13 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost)
* actually sent
*/
if (unlikely(!ibmvfc_valid_event(&vhost->pool, evt))) {
- dev_err(vhost->dev, "Returned correlation_token 0x%08lx is invalid!\n",
+ dev_err(vhost->dev, "Returned correlation_token 0x%08llx is invalid!\n",
crq->ioba);
return;
}
if (unlikely(atomic_read(&evt->free))) {
- dev_err(vhost->dev, "Received duplicate correlation_token 0x%08lx!\n",
+ dev_err(vhost->dev, "Received duplicate correlation_token 0x%08llx!\n",
crq->ioba);
return;
}
@@ -3259,7 +3259,7 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id)
tgt = mempool_alloc(vhost->tgt_pool, GFP_KERNEL);
if (!tgt) {
- dev_err(vhost->dev, "Target allocation failure for scsi id %08lx\n",
+ dev_err(vhost->dev, "Target allocation failure for scsi id %08llx\n",
scsi_id);
return -ENOMEM;
}
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index babdf3db59df..87dafd0f8d44 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -691,13 +691,13 @@ struct ibmvfc_host {
#define DBG_CMD(CMD) do { if (ibmvfc_debug) CMD; } while (0)
#define tgt_dbg(t, fmt, ...) \
- DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__))
+ DBG_CMD(dev_info((t)->vhost->dev, "%llX: " fmt, (t)->scsi_id, ##__VA_ARGS__))
#define tgt_info(t, fmt, ...) \
- dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
+ dev_info((t)->vhost->dev, "%llX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
#define tgt_err(t, fmt, ...) \
- dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
+ dev_err((t)->vhost->dev, "%llX: " fmt, (t)->scsi_id, ##__VA_ARGS__)
#define ibmvfc_dbg(vhost, ...) \
DBG_CMD(dev_info((vhost)->dev, ##__VA_ARGS__))
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 868d35ea01bb..74d07d137dae 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -89,6 +89,7 @@ static int max_id = 64;
static int max_channel = 3;
static int init_timeout = 5;
static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
+static int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2;
static struct scsi_transport_template *ibmvscsi_transport_template;
@@ -1060,7 +1061,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
}
sdev_printk(KERN_INFO, cmd->device,
- "aborting command. lun 0x%lx, tag 0x%lx\n",
+ "aborting command. lun 0x%llx, tag 0x%llx\n",
(((u64) lun) << 48), (u64) found_evt);
wait_for_completion(&evt->comp);
@@ -1081,7 +1082,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
if (rsp_rc) {
if (printk_ratelimit())
sdev_printk(KERN_WARNING, cmd->device,
- "abort code %d for task tag 0x%lx\n",
+ "abort code %d for task tag 0x%llx\n",
rsp_rc, tsk_mgmt->task_tag);
return FAILED;
}
@@ -1101,12 +1102,12 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
if (found_evt == NULL) {
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
- sdev_printk(KERN_INFO, cmd->device, "aborted task tag 0x%lx completed\n",
+ sdev_printk(KERN_INFO, cmd->device, "aborted task tag 0x%llx completed\n",
tsk_mgmt->task_tag);
return SUCCESS;
}
- sdev_printk(KERN_INFO, cmd->device, "successfully aborted task tag 0x%lx\n",
+ sdev_printk(KERN_INFO, cmd->device, "successfully aborted task tag 0x%llx\n",
tsk_mgmt->task_tag);
cmd->result = (DID_ABORT << 16);
@@ -1181,7 +1182,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
return FAILED;
}
- sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
+ sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%llx\n",
(((u64) lun) << 48));
wait_for_completion(&evt->comp);
@@ -1202,7 +1203,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
if (rsp_rc) {
if (printk_ratelimit())
sdev_printk(KERN_WARNING, cmd->device,
- "reset code %d for task tag 0x%lx\n",
+ "reset code %d for task tag 0x%llx\n",
rsp_rc, tsk_mgmt->task_tag);
return FAILED;
}
@@ -1633,7 +1634,7 @@ static struct scsi_host_template driver_template = {
static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
{
/* iu_storage data allocated in initialize_event_pool */
- unsigned long desired_io = max_requests * sizeof(union viosrp_iu);
+ unsigned long desired_io = max_events * sizeof(union viosrp_iu);
/* add io space for sg data */
desired_io += (IBMVSCSI_MAX_SECTORS_DEFAULT * 512 *
@@ -1657,7 +1658,6 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
vdev->dev.driver_data = NULL;
- driver_template.can_queue = max_requests - 2;
host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
if (!host) {
dev_err(&vdev->dev, "couldn't allocate host data\n");
@@ -1673,12 +1673,12 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
atomic_set(&hostdata->request_limit, -1);
hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT;
- rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_requests);
+ rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events);
if (rc != 0 && rc != H_RESOURCE) {
dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
goto init_crq_failed;
}
- if (initialize_event_pool(&hostdata->pool, max_requests, hostdata) != 0) {
+ if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) {
dev_err(&vdev->dev, "couldn't initialize event pool\n");
goto init_pool_failed;
}
@@ -1730,7 +1730,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
add_host_failed:
release_event_pool(&hostdata->pool, hostdata);
init_pool_failed:
- ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_requests);
+ ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events);
init_crq_failed:
scsi_host_put(host);
scsi_host_alloc_failed:
@@ -1742,7 +1742,7 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
release_event_pool(&hostdata->pool, hostdata);
ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
- max_requests);
+ max_events);
srp_remove_host(hostdata->host);
scsi_remove_host(hostdata->host);
@@ -1779,6 +1779,10 @@ int __init ibmvscsi_module_init(void)
{
int ret;
+ /* Ensure we have two requests to do error recovery */
+ driver_template.can_queue = max_requests;
+ max_events = max_requests + 2;
+
if (firmware_has_feature(FW_FEATURE_ISERIES))
ibmvscsi_ops = &iseriesvscsi_ops;
else if (firmware_has_feature(FW_FEATURE_VIO))
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 0edfb1fa63ce..07829009a8be 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -2184,7 +2184,7 @@ static void ipr_dump_location_data(struct ipr_ioa_cfg *ioa_cfg,
sizeof(struct ipr_dump_entry_header);
driver_dump->location_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_ASCII;
driver_dump->location_entry.hdr.id = IPR_DUMP_LOCATION_ID;
- strcpy(driver_dump->location_entry.location, ioa_cfg->pdev->dev.bus_id);
+ strcpy(driver_dump->location_entry.location, dev_name(&ioa_cfg->pdev->dev));
driver_dump->hdr.num_entries++;
}
@@ -4912,7 +4912,7 @@ static int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
if (res && ipr_is_gata(res)) {
if (cmd == HDIO_GET_IDENTITY)
return -ENOTTY;
- return ata_scsi_ioctl(sdev, cmd, arg);
+ return ata_sas_scsi_ioctl(res->sata_port->ap, sdev, cmd, arg);
}
return -EINVAL;
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 59459141b437..8f872f816fe4 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -1272,7 +1272,7 @@ struct ipr_dump_entry_header {
struct ipr_dump_location_entry {
struct ipr_dump_entry_header hdr;
- u8 location[BUS_ID_SIZE];
+ u8 location[20];
}__attribute__((packed));
struct ipr_dump_trace_entry {
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
index 3126824da36d..4a4e6954ec79 100644
--- a/drivers/scsi/lasi700.c
+++ b/drivers/scsi/lasi700.c
@@ -103,8 +103,7 @@ lasi700_probe(struct parisc_device *dev)
hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
if (!hostdata) {
- printk(KERN_ERR "%s: Failed to allocate host data\n",
- dev->dev.bus_id);
+ dev_printk(KERN_ERR, dev, "Failed to allocate host data\n");
return -ENOMEM;
}
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index a745f91d2928..e7705d3532c9 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -177,7 +177,6 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
struct iscsi_segment *segment, int recv,
unsigned copied)
{
- static unsigned char padbuf[ISCSI_PAD_LEN];
struct scatterlist sg;
unsigned int pad;
@@ -233,7 +232,7 @@ int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn,
debug_tcp("consume %d pad bytes\n", pad);
segment->total_size += pad;
segment->size = pad;
- segment->data = padbuf;
+ segment->data = segment->padbuf;
return 0;
}
}
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index 709a6f75ca9d..facc5bfcf7db 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -169,7 +169,7 @@ int sas_notify_lldd_dev_found(struct domain_device *dev)
if (res) {
printk("sas: driver on pcidev %s cannot handle "
"device %llx, error:%d\n",
- sas_ha->dev->bus_id,
+ dev_name(sas_ha->dev),
SAS_ADDR(dev->sas_addr), res);
}
}
diff --git a/drivers/scsi/libsas/sas_dump.c b/drivers/scsi/libsas/sas_dump.c
index bf34a236f946..c17c25030f1c 100644
--- a/drivers/scsi/libsas/sas_dump.c
+++ b/drivers/scsi/libsas/sas_dump.c
@@ -56,7 +56,7 @@ void sas_dprint_phye(int phyid, enum phy_event pe)
void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he)
{
- SAS_DPRINTK("ha %s: %s event\n", sas_ha->dev->bus_id,
+ SAS_DPRINTK("ha %s: %s event\n", dev_name(sas_ha->dev),
sas_hae_str[he]);
}
diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c
index 16f93123271e..d110a366c48a 100644
--- a/drivers/scsi/libsas/sas_host_smp.c
+++ b/drivers/scsi/libsas/sas_host_smp.c
@@ -199,8 +199,8 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
break;
case SMP_DISCOVER:
- req->data_len =- 16;
- if (req->data_len < 0) {
+ req->data_len -= 16;
+ if ((int)req->data_len < 0) {
req->data_len = 0;
error = -EINVAL;
goto out;
@@ -215,8 +215,8 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
break;
case SMP_REPORT_PHY_SATA:
- req->data_len =- 16;
- if (req->data_len < 0) {
+ req->data_len -= 16;
+ if ((int)req->data_len < 0) {
req->data_len = 0;
error = -EINVAL;
goto out;
@@ -238,8 +238,8 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req,
break;
case SMP_PHY_CONTROL:
- req->data_len =- 44;
- if (req->data_len < 0) {
+ req->data_len -= 44;
+ if ((int)req->data_len < 0) {
req->data_len = 0;
error = -EINVAL;
goto out;
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
index 139935a121b4..e6ac59c023f1 100644
--- a/drivers/scsi/libsas/sas_port.c
+++ b/drivers/scsi/libsas/sas_port.c
@@ -113,7 +113,7 @@ static void sas_form_port(struct asd_sas_phy *phy)
sas_port_add_phy(port->port, phy->phy);
SAS_DPRINTK("%s added to %s, phy_mask:0x%x (%16llx)\n",
- phy->phy->dev.bus_id,port->port->dev.bus_id,
+ dev_name(&phy->phy->dev), dev_name(&port->port->dev),
port->phy_mask,
SAS_ADDR(port->attached_sas_addr));
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 744838780ada..1c558d3bce18 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -717,7 +717,7 @@ int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
struct domain_device *dev = sdev_to_domain_dev(sdev);
if (dev_is_sata(dev))
- return ata_scsi_ioctl(sdev, cmd, arg);
+ return ata_sas_scsi_ioctl(dev->sata_dev.ap, sdev, cmd, arg);
return -EINVAL;
}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 8c64494444bf..311ed6dea726 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -1964,10 +1964,10 @@ lpfc_set_disctmo(struct lpfc_vport *vport)
uint32_t tmo;
if (vport->port_state == LPFC_LOCAL_CFG_LINK) {
- /* For FAN, timeout should be greater then edtov */
+ /* For FAN, timeout should be greater than edtov */
tmo = (((phba->fc_edtov + 999) / 1000) + 1);
} else {
- /* Normal discovery timeout should be > then ELS/CT timeout
+ /* Normal discovery timeout should be > than ELS/CT timeout
* FC spec states we need 3 * ratov for CT requests
*/
tmo = ((phba->fc_ratov * 3) + 3);
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 4c77038c8f1c..6c867311cef1 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1795,12 +1795,13 @@ lpfc_block_mgmt_io(struct lpfc_hba * phba)
int
lpfc_online(struct lpfc_hba *phba)
{
- struct lpfc_vport *vport = phba->pport;
+ struct lpfc_vport *vport;
struct lpfc_vport **vports;
int i;
if (!phba)
return 0;
+ vport = phba->pport;
if (!(vport->fc_flag & FC_OFFLINE_MODE))
return 0;
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 01dfdc8696f8..a36a120561e2 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -420,7 +420,7 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
if (unlikely(pring->local_getidx >= max_cmd_idx)) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0315 Ring %d issue: portCmdGet %d "
- "is bigger then cmd ring %d\n",
+ "is bigger than cmd ring %d\n",
pring->ringno,
pring->local_getidx, max_cmd_idx);
@@ -1628,12 +1628,12 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno];
/*
- * Ring <ringno> handler: portRspPut <portRspPut> is bigger then
+ * Ring <ringno> handler: portRspPut <portRspPut> is bigger than
* rsp ring <portRspMax>
*/
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0312 Ring %d handler: portRspPut %d "
- "is bigger then rsp ring %d\n",
+ "is bigger than rsp ring %d\n",
pring->ringno, le32_to_cpu(pgp->rspPutInx),
pring->numRiocb);
@@ -2083,12 +2083,12 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
portRspPut = le32_to_cpu(pgp->rspPutInx);
if (portRspPut >= portRspMax) {
/*
- * Ring <ringno> handler: portRspPut <portRspPut> is bigger then
+ * Ring <ringno> handler: portRspPut <portRspPut> is bigger than
* rsp ring <portRspMax>
*/
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"0303 Ring %d handler: portRspPut %d "
- "is bigger then rsp ring %d\n",
+ "is bigger than rsp ring %d\n",
pring->ringno, portRspPut, portRspMax);
phba->link_state = LPFC_HBA_ERROR;
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 7dc62deb4087..9fdcd60c5493 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -1967,8 +1967,8 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor)
scb->state |= aor;
/*
- * Check if this command has firmare owenership. If
- * yes, we cannot reset this command. Whenever, f/w
+ * Check if this command has firmware ownership. If
+ * yes, we cannot reset this command. Whenever f/w
* completes this command, we will return appropriate
* status from ISR.
*/
diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
index 1dd70d7a4947..23e5a876bb10 100644
--- a/drivers/scsi/mvsas.c
+++ b/drivers/scsi/mvsas.c
@@ -2959,7 +2959,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
/* enable auto port detection */
mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN);
- msleep(100);
+ msleep(1100);
/* init and reset phys */
for (i = 0; i < mvi->chip->n_phy; i++) {
u32 lo = be32_to_cpu(*(u32 *)&mvi->sas_addr[4]);
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index 165ff884f48e..67cde0138061 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -114,7 +114,7 @@ static int aha152x_probe(struct pcmcia_device *link)
link->io.NumPorts1 = 0x20;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
link->io.IOAddrLines = 10;
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c
index ce48e2d0193c..ca0dd33497ec 100644
--- a/drivers/scsi/ps3rom.c
+++ b/drivers/scsi/ps3rom.c
@@ -290,11 +290,11 @@ static irqreturn_t ps3rom_interrupt(int irq, void *data)
if (tag != dev->tag)
dev_err(&dev->sbd.core,
- "%s:%u: tag mismatch, got %lx, expected %lx\n",
+ "%s:%u: tag mismatch, got %llx, expected %llx\n",
__func__, __LINE__, tag, dev->tag);
if (res) {
- dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+ dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n",
__func__, __LINE__, res, status);
return IRQ_HANDLED;
}
@@ -364,7 +364,7 @@ static int __devinit ps3rom_probe(struct ps3_system_bus_device *_dev)
if (dev->blk_size != CD_FRAMESIZE) {
dev_err(&dev->sbd.core,
- "%s:%u: cannot handle block size %lu\n", __func__,
+ "%s:%u: cannot handle block size %llu\n", __func__,
__LINE__, dev->blk_size);
return -EINVAL;
}
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 8cb9240596ab..df09820e8916 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -128,7 +128,7 @@
- Integrate ql12160_set_target_parameters() with 1280 version
- Make qla1280_setup() non static
- Do not call qla1280_check_for_dead_scsi_bus() on every I/O request
- sent to the card - this command pauses the firmare!!!
+ sent to the card - this command pauses the firmware!!!
Rev 3.23.15 Beta March 19, 2002, Jes Sorensen
- Clean up qla1280.h - remove obsolete QL_DEBUG_LEVEL_x definitions
- Remove a pile of pointless and confusing (srb_t **) and
@@ -659,7 +659,7 @@ static int qla1280_read_nvram(struct scsi_qla_host *ha)
/* The firmware interface is, um, interesting, in that the
* actual firmware image on the chip is little endian, thus,
* the process of taking that image to the CPU would end up
- * little endian. However, the firmare interface requires it
+ * little endian. However, the firmware interface requires it
* to be read a word (two bytes) at a time.
*
* The net result of this would be that the word (and
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index cd53627cc761..c7acef50d5da 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -303,7 +303,7 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
else if (start == (ha->flt_region_boot * 4) ||
start == (ha->flt_region_fw * 4))
valid = 1;
- else if (IS_QLA25XX(ha) &&
+ else if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) &&
start == (ha->flt_region_vpd_nvram * 4))
valid = 1;
if (!valid) {
@@ -815,6 +815,21 @@ qla2x00_total_isp_aborts_show(struct device *dev,
ha->qla_stats.total_isp_aborts);
}
+static ssize_t
+qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!IS_QLA81XX(ha))
+ return snprintf(buf, PAGE_SIZE, "\n");
+
+ return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x (%x)\n",
+ ha->mpi_version[0], ha->mpi_version[1], ha->mpi_version[2],
+ ha->mpi_version[3], ha->mpi_capabilities);
+}
+
static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
@@ -839,6 +854,7 @@ static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show,
NULL);
static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show,
NULL);
+static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL);
struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_driver_version,
@@ -858,6 +874,7 @@ struct device_attribute *qla2x00_host_attrs[] = {
&dev_attr_optrom_fcode_version,
&dev_attr_optrom_fw_version,
&dev_attr_total_isp_aborts,
+ &dev_attr_mpi_version,
NULL,
};
@@ -892,6 +909,9 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
case PORT_SPEED_8GB:
speed = FC_PORTSPEED_8GBIT;
break;
+ case PORT_SPEED_10GB:
+ speed = FC_PORTSPEED_10GBIT;
+ break;
}
fc_host_speed(shost) = speed;
}
@@ -1382,7 +1402,9 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha)
fc_host_max_npiv_vports(vha->host) = ha->max_npiv_vports;
fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count;
- if (IS_QLA25XX(ha))
+ if (IS_QLA81XX(ha))
+ speed = FC_PORTSPEED_10GBIT;
+ else if (IS_QLA25XX(ha))
speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT |
FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
else if (IS_QLA24XX_TYPE(ha))
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 1cf77772623b..34760f8d4f17 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -310,6 +310,76 @@ qla2xxx_read_window(struct device_reg_2xxx __iomem *reg, uint32_t count,
*buf++ = htons(RD_REG_WORD(dmp_reg++));
}
+static inline void *
+qla24xx_copy_eft(struct qla_hw_data *ha, void *ptr)
+{
+ if (!ha->eft)
+ return ptr;
+
+ memcpy(ptr, ha->eft, ntohl(ha->fw_dump->eft_size));
+ return ptr + ntohl(ha->fw_dump->eft_size);
+}
+
+static inline void *
+qla25xx_copy_fce(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
+{
+ uint32_t cnt;
+ uint32_t *iter_reg;
+ struct qla2xxx_fce_chain *fcec = ptr;
+
+ if (!ha->fce)
+ return ptr;
+
+ *last_chain = &fcec->type;
+ fcec->type = __constant_htonl(DUMP_CHAIN_FCE);
+ 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));
+
+ return iter_reg;
+}
+
+static inline void *
+qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
+{
+ uint32_t cnt, que_idx;
+ uint8_t req_cnt, rsp_cnt, que_cnt;
+ struct qla2xxx_mq_chain *mq = ptr;
+ struct device_reg_25xxmq __iomem *reg;
+
+ if (!ha->mqenable)
+ return ptr;
+
+ mq = ptr;
+ *last_chain = &mq->type;
+ mq->type = __constant_htonl(DUMP_CHAIN_MQ);
+ mq->chain_size = __constant_htonl(sizeof(struct qla2xxx_mq_chain));
+
+ req_cnt = find_first_zero_bit(ha->req_qid_map, ha->max_queues);
+ rsp_cnt = find_first_zero_bit(ha->rsp_qid_map, ha->max_queues);
+ que_cnt = req_cnt > rsp_cnt ? req_cnt : rsp_cnt;
+ mq->count = htonl(que_cnt);
+ for (cnt = 0; cnt < que_cnt; cnt++) {
+ reg = (struct device_reg_25xxmq *) ((void *)
+ ha->mqiobase + cnt * QLA_QUE_PAGE);
+ que_idx = cnt * 4;
+ mq->qregs[que_idx] = htonl(RD_REG_DWORD(&reg->req_q_in));
+ mq->qregs[que_idx+1] = htonl(RD_REG_DWORD(&reg->req_q_out));
+ mq->qregs[que_idx+2] = htonl(RD_REG_DWORD(&reg->rsp_q_in));
+ mq->qregs[que_idx+3] = htonl(RD_REG_DWORD(&reg->rsp_q_out));
+ }
+
+ return ptr + sizeof(struct qla2xxx_mq_chain);
+}
+
/**
* qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
* @ha: HA context
@@ -913,8 +983,8 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
goto qla24xx_fw_dump_failed_0;
nxt = qla2xxx_copy_queues(ha, nxt);
- if (ha->eft)
- memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
+
+ qla24xx_copy_eft(ha, nxt);
qla24xx_fw_dump_failed_0:
if (rval != QLA_SUCCESS) {
@@ -942,19 +1012,14 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
uint32_t risc_address;
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
- struct device_reg_25xxmq __iomem *reg25;
uint32_t __iomem *dmp_reg;
uint32_t *iter_reg;
uint16_t __iomem *mbx_reg;
unsigned long flags;
struct qla25xx_fw_dump *fw;
uint32_t ext_mem_cnt;
- void *nxt;
- struct qla2xxx_fce_chain *fcec;
- struct qla2xxx_mq_chain *mq = NULL;
- uint32_t qreg_size;
- uint8_t req_cnt, rsp_cnt, que_cnt;
- uint32_t que_idx;
+ void *nxt, *nxt_chain;
+ uint32_t *last_chain = NULL;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
risc_address = ext_mem_cnt = 0;
@@ -1001,28 +1066,6 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
fw->pcie_regs[3] = htonl(RD_REG_DWORD(&reg->iobase_window));
- /* Multi queue registers */
- if (ha->mqenable) {
- qreg_size = sizeof(struct qla2xxx_mq_chain);
- mq = kzalloc(qreg_size, GFP_KERNEL);
- if (!mq)
- goto qla25xx_fw_dump_failed_0;
- req_cnt = find_first_zero_bit(ha->req_qid_map, ha->max_queues);
- rsp_cnt = find_first_zero_bit(ha->rsp_qid_map, ha->max_queues);
- que_cnt = req_cnt > rsp_cnt ? req_cnt : rsp_cnt;
- mq->count = htonl(que_cnt);
- mq->chain_size = htonl(qreg_size);
- mq->type = __constant_htonl(DUMP_CHAIN_MQ);
- for (cnt = 0; cnt < que_cnt; cnt++) {
- reg25 = (struct device_reg_25xxmq *) ((void *)
- ha->mqiobase + cnt * QLA_QUE_PAGE);
- que_idx = cnt * 4;
- mq->qregs[que_idx] = htonl(reg25->req_q_in);
- mq->qregs[que_idx+1] = htonl(reg25->req_q_out);
- mq->qregs[que_idx+2] = htonl(reg25->rsp_q_in);
- mq->qregs[que_idx+3] = htonl(reg25->rsp_q_out);
- }
- }
WRT_REG_DWORD(&reg->iobase_window, 0x00);
RD_REG_DWORD(&reg->iobase_window);
@@ -1240,6 +1283,10 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg);
qla24xx_read_window(reg, 0x6F00, 16, iter_reg);
+ /* Multi queue registers */
+ nxt_chain = qla25xx_copy_mq(ha, (void *)ha->fw_dump + ha->chain_offset,
+ &last_chain);
+
rval = qla24xx_soft_reset(ha);
if (rval != QLA_SUCCESS)
goto qla25xx_fw_dump_failed_0;
@@ -1249,39 +1296,341 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, 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;
+ nxt = qla24xx_copy_eft(ha, nxt);
+
+ /* Chain entries -- started with MQ. */
+ qla25xx_copy_fce(ha, nxt_chain, &last_chain);
+ if (last_chain) {
+ ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
+ *last_chain |= __constant_htonl(DUMP_CHAIN_LAST);
+ }
- ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
+qla25xx_fw_dump_failed_0:
+ if (rval != QLA_SUCCESS) {
+ qla_printk(KERN_WARNING, ha,
+ "Failed to dump firmware (%x)!!!\n", rval);
+ ha->fw_dumped = 0;
- if (ha->mqenable) {
- nxt = nxt + ntohl(ha->fw_dump->eft_size);
- memcpy(nxt, mq, qreg_size);
- kfree(mq);
- fcec = nxt + qreg_size;
} else {
- fcec = nxt + ntohl(ha->fw_dump->eft_size);
+ qla_printk(KERN_INFO, ha,
+ "Firmware dump saved to temp buffer (%ld/%p).\n",
+ base_vha->host_no, ha->fw_dump);
+ ha->fw_dumped = 1;
}
- 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]);
+qla25xx_fw_dump_failed:
+ if (!hardware_locked)
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
- memcpy(iter_reg, ha->fce, ntohl(fcec->size));
+void
+qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
+{
+ int rval;
+ uint32_t cnt;
+ uint32_t risc_address;
+ struct qla_hw_data *ha = vha->hw;
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ uint32_t __iomem *dmp_reg;
+ uint32_t *iter_reg;
+ uint16_t __iomem *mbx_reg;
+ unsigned long flags;
+ struct qla81xx_fw_dump *fw;
+ uint32_t ext_mem_cnt;
+ void *nxt, *nxt_chain;
+ uint32_t *last_chain = NULL;
+ struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
-qla25xx_fw_dump_failed_0:
+ risc_address = ext_mem_cnt = 0;
+ flags = 0;
+
+ if (!hardware_locked)
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ if (!ha->fw_dump) {
+ qla_printk(KERN_WARNING, ha,
+ "No buffer available for dump!!!\n");
+ goto qla81xx_fw_dump_failed;
+ }
+
+ if (ha->fw_dumped) {
+ qla_printk(KERN_WARNING, ha,
+ "Firmware has been previously dumped (%p) -- ignoring "
+ "request...\n", ha->fw_dump);
+ goto qla81xx_fw_dump_failed;
+ }
+ fw = &ha->fw_dump->isp.isp81;
+ qla2xxx_prep_dump(ha, ha->fw_dump);
+
+ fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
+
+ /* Pause RISC. */
+ rval = qla24xx_pause_risc(reg);
+ if (rval != QLA_SUCCESS)
+ goto qla81xx_fw_dump_failed_0;
+
+ /* Host/Risc registers. */
+ iter_reg = fw->host_risc_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7000, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7010, 16, iter_reg);
+
+ /* PCIe registers. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);
+ RD_REG_DWORD(&reg->iobase_addr);
+ WRT_REG_DWORD(&reg->iobase_window, 0x01);
+ dmp_reg = &reg->iobase_c4;
+ fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++));
+ fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++));
+ fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg));
+ fw->pcie_regs[3] = htonl(RD_REG_DWORD(&reg->iobase_window));
+
+ WRT_REG_DWORD(&reg->iobase_window, 0x00);
+ RD_REG_DWORD(&reg->iobase_window);
+
+ /* Host interface registers. */
+ dmp_reg = &reg->flash_addr;
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Disable interrupts. */
+ WRT_REG_DWORD(&reg->ictrl, 0);
+ RD_REG_DWORD(&reg->ictrl);
+
+ /* Shadow registers. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+ RD_REG_DWORD(&reg->iobase_addr);
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+ fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+ fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+ fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+ fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+ fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+ fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+ fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0700000);
+ fw->shadow_reg[7] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0800000);
+ fw->shadow_reg[8] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0900000);
+ fw->shadow_reg[9] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0A00000);
+ fw->shadow_reg[10] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ /* RISC I/O register. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0010);
+ fw->risc_io_reg = htonl(RD_REG_DWORD(&reg->iobase_window));
+
+ /* Mailbox registers. */
+ mbx_reg = &reg->mailbox0;
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+
+ /* Transfer sequence registers. */
+ iter_reg = fw->xseq_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg);
+ qla24xx_read_window(reg, 0xBF70, 16, iter_reg);
+
+ iter_reg = fw->xseq_0_reg;
+ iter_reg = qla24xx_read_window(reg, 0xBFC0, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xBFD0, 16, iter_reg);
+ qla24xx_read_window(reg, 0xBFE0, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg);
+
+ /* Receive sequence registers. */
+ iter_reg = fw->rseq_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg);
+ qla24xx_read_window(reg, 0xFF70, 16, iter_reg);
+
+ iter_reg = fw->rseq_0_reg;
+ iter_reg = qla24xx_read_window(reg, 0xFFC0, 16, iter_reg);
+ qla24xx_read_window(reg, 0xFFD0, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg);
+ qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg);
+
+ /* Auxiliary sequence registers. */
+ iter_reg = fw->aseq_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0xB000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB050, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0xB060, 16, iter_reg);
+ qla24xx_read_window(reg, 0xB070, 16, iter_reg);
+
+ iter_reg = fw->aseq_0_reg;
+ iter_reg = qla24xx_read_window(reg, 0xB0C0, 16, iter_reg);
+ qla24xx_read_window(reg, 0xB0D0, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0xB0E0, 16, fw->aseq_1_reg);
+ qla24xx_read_window(reg, 0xB0F0, 16, fw->aseq_2_reg);
+
+ /* Command DMA registers. */
+ qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg);
+
+ /* Queues. */
+ iter_reg = fw->req0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->resp0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->req1_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg);
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Transmit DMA registers. */
+ iter_reg = fw->xmt0_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7610, 16, iter_reg);
+
+ iter_reg = fw->xmt1_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7630, 16, iter_reg);
+
+ iter_reg = fw->xmt2_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7650, 16, iter_reg);
+
+ iter_reg = fw->xmt3_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7670, 16, iter_reg);
+
+ iter_reg = fw->xmt4_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7690, 16, iter_reg);
+
+ qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg);
+
+ /* Receive DMA registers. */
+ iter_reg = fw->rcvt0_data_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7710, 16, iter_reg);
+
+ iter_reg = fw->rcvt1_data_dma_reg;
+ iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg);
+ qla24xx_read_window(reg, 0x7730, 16, iter_reg);
+
+ /* RISC registers. */
+ iter_reg = fw->risc_gp_reg;
+ iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg);
+ qla24xx_read_window(reg, 0x0F70, 16, iter_reg);
+
+ /* Local memory controller registers. */
+ iter_reg = fw->lmc_reg;
+ iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x3060, 16, iter_reg);
+ qla24xx_read_window(reg, 0x3070, 16, iter_reg);
+
+ /* Fibre Protocol Module registers. */
+ iter_reg = fw->fpm_hdw_reg;
+ iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x40B0, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x40C0, 16, iter_reg);
+ qla24xx_read_window(reg, 0x40D0, 16, iter_reg);
+
+ /* Frame Buffer registers. */
+ iter_reg = fw->fb_hdw_reg;
+ iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg);
+ iter_reg = qla24xx_read_window(reg, 0x61C0, 16, iter_reg);
+ qla24xx_read_window(reg, 0x6F00, 16, iter_reg);
+
+ /* Multi queue registers */
+ nxt_chain = qla25xx_copy_mq(ha, (void *)ha->fw_dump + ha->chain_offset,
+ &last_chain);
+
+ rval = qla24xx_soft_reset(ha);
+ if (rval != QLA_SUCCESS)
+ goto qla81xx_fw_dump_failed_0;
+
+ rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram),
+ &nxt);
+ if (rval != QLA_SUCCESS)
+ goto qla81xx_fw_dump_failed_0;
+
+ nxt = qla2xxx_copy_queues(ha, nxt);
+
+ nxt = qla24xx_copy_eft(ha, nxt);
+
+ /* Chain entries -- started with MQ. */
+ qla25xx_copy_fce(ha, nxt_chain, &last_chain);
+ if (last_chain) {
+ ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
+ *last_chain |= __constant_htonl(DUMP_CHAIN_LAST);
+ }
+
+qla81xx_fw_dump_failed_0:
if (rval != QLA_SUCCESS) {
qla_printk(KERN_WARNING, ha,
"Failed to dump firmware (%x)!!!\n", rval);
@@ -1294,10 +1643,11 @@ qla25xx_fw_dump_failed_0:
ha->fw_dumped = 1;
}
-qla25xx_fw_dump_failed:
+qla81xx_fw_dump_failed:
if (!hardware_locked)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
+
/****************************************************************************/
/* Driver Debug Functions. */
/****************************************************************************/
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index c1794a70a45f..f660dd70b72e 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -251,6 +251,45 @@ struct qla25xx_fw_dump {
uint32_t ext_mem[1];
};
+struct qla81xx_fw_dump {
+ uint32_t host_status;
+ uint32_t host_risc_reg[32];
+ uint32_t pcie_regs[4];
+ uint32_t host_reg[32];
+ uint32_t shadow_reg[11];
+ uint32_t risc_io_reg;
+ uint16_t mailbox_reg[32];
+ uint32_t xseq_gp_reg[128];
+ uint32_t xseq_0_reg[48];
+ uint32_t xseq_1_reg[16];
+ uint32_t rseq_gp_reg[128];
+ uint32_t rseq_0_reg[32];
+ uint32_t rseq_1_reg[16];
+ uint32_t rseq_2_reg[16];
+ uint32_t aseq_gp_reg[128];
+ uint32_t aseq_0_reg[32];
+ uint32_t aseq_1_reg[16];
+ uint32_t aseq_2_reg[16];
+ uint32_t cmd_dma_reg[16];
+ uint32_t req0_dma_reg[15];
+ uint32_t resp0_dma_reg[15];
+ uint32_t req1_dma_reg[15];
+ uint32_t xmt0_dma_reg[32];
+ uint32_t xmt1_dma_reg[32];
+ uint32_t xmt2_dma_reg[32];
+ uint32_t xmt3_dma_reg[32];
+ uint32_t xmt4_dma_reg[32];
+ uint32_t xmt_data_dma_reg[16];
+ uint32_t rcvt0_data_dma_reg[32];
+ uint32_t rcvt1_data_dma_reg[32];
+ uint32_t risc_gp_reg[128];
+ uint32_t lmc_reg[128];
+ uint32_t fpm_hdw_reg[224];
+ uint32_t fb_hdw_reg[208];
+ uint32_t code_ram[0x2000];
+ uint32_t ext_mem[1];
+};
+
#define EFT_NUM_BUFFERS 4
#define EFT_BYTES_PER_BUFFER 0x4000
#define EFT_SIZE ((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS))
@@ -313,5 +352,6 @@ struct qla2xxx_fw_dump {
struct qla2300_fw_dump isp23;
struct qla24xx_fw_dump isp24;
struct qla25xx_fw_dump isp25;
+ struct qla81xx_fw_dump isp81;
} isp;
};
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index a29c95204975..023ee77fb027 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -187,7 +187,6 @@ struct req_que;
* SCSI Request Block
*/
typedef struct srb {
- struct scsi_qla_host *vha; /* HA the SP is queued on */
struct req_que *que;
struct fc_port *fcport;
@@ -2136,7 +2135,6 @@ struct qla_msix_entry {
/* Work events. */
enum qla_work_type {
QLA_EVT_AEN,
- QLA_EVT_HWE_LOG,
};
@@ -2151,10 +2149,6 @@ struct qla_work_evt {
enum fc_host_event_code code;
u32 data;
} aen;
- struct {
- uint16_t code;
- uint16_t d1, d2, d3;
- } hwe;
} u;
};
@@ -2309,6 +2303,7 @@ struct qla_hw_data {
#define PORT_SPEED_2GB 0x01
#define PORT_SPEED_4GB 0x03
#define PORT_SPEED_8GB 0x04
+#define PORT_SPEED_10GB 0x13
uint16_t link_data_rate; /* F/W operating speed */
uint8_t current_topology;
@@ -2328,6 +2323,7 @@ struct qla_hw_data {
#define PCI_DEVICE_ID_QLOGIC_ISP2532 0x2532
#define PCI_DEVICE_ID_QLOGIC_ISP8432 0x8432
+#define PCI_DEVICE_ID_QLOGIC_ISP8001 0x8001
uint32_t device_type;
#define DT_ISP2100 BIT_0
#define DT_ISP2200 BIT_1
@@ -2342,7 +2338,8 @@ struct qla_hw_data {
#define DT_ISP5432 BIT_10
#define DT_ISP2532 BIT_11
#define DT_ISP8432 BIT_12
-#define DT_ISP_LAST (DT_ISP8432 << 1)
+#define DT_ISP8001 BIT_13
+#define DT_ISP_LAST (DT_ISP8001 << 1)
#define DT_IIDMA BIT_26
#define DT_FWI2 BIT_27
@@ -2364,6 +2361,7 @@ struct qla_hw_data {
#define IS_QLA5432(ha) (DT_MASK(ha) & DT_ISP5432)
#define IS_QLA2532(ha) (DT_MASK(ha) & DT_ISP2532)
#define IS_QLA8432(ha) (DT_MASK(ha) & DT_ISP8432)
+#define IS_QLA8001(ha) (DT_MASK(ha) & DT_ISP8001)
#define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
IS_QLA6312(ha) || IS_QLA6322(ha))
@@ -2373,8 +2371,11 @@ struct qla_hw_data {
#define IS_QLA84XX(ha) (IS_QLA8432(ha))
#define IS_QLA24XX_TYPE(ha) (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
IS_QLA84XX(ha))
+#define IS_QLA81XX(ha) (IS_QLA8001(ha))
#define IS_QLA2XXX_MIDTYPE(ha) (IS_QLA24XX(ha) || IS_QLA84XX(ha) || \
- IS_QLA25XX(ha))
+ IS_QLA25XX(ha) || IS_QLA81XX(ha))
+#define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && \
+ (ha)->flags.msix_enabled)
#define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA)
#define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2)
@@ -2472,6 +2473,9 @@ struct qla_hw_data {
uint8_t fw_seriallink_options[4];
uint16_t fw_seriallink_options24[4];
+ uint8_t mpi_version[4];
+ uint32_t mpi_capabilities;
+
/* Firmware dump information. */
struct qla2xxx_fw_dump *fw_dump;
uint32_t fw_dump_len;
@@ -2480,6 +2484,7 @@ struct qla_hw_data {
dma_addr_t eft_dma;
void *eft;
+ uint32_t chain_offset;
struct dentry *dfs_dir;
struct dentry *dfs_fce;
dma_addr_t fce_dma;
@@ -2489,10 +2494,6 @@ struct qla_hw_data {
uint64_t fce_wr, fce_rd;
struct mutex fce_mutex;
- uint32_t hw_event_start;
- uint32_t hw_event_ptr;
- uint32_t hw_event_pause_errors;
-
uint32_t pci_attr;
uint16_t chip_revision;
@@ -2522,6 +2523,12 @@ struct qla_hw_data {
uint8_t fcode_revision[16];
uint32_t fw_revision[4];
+ /* Offsets for flash/nvram access (set to ~0 if not used). */
+ uint32_t flash_conf_off;
+ uint32_t flash_data_off;
+ uint32_t nvram_conf_off;
+ uint32_t nvram_data_off;
+
uint32_t fdt_wrt_disable;
uint32_t fdt_erase_cmd;
uint32_t fdt_block_size;
@@ -2533,7 +2540,6 @@ struct qla_hw_data {
uint32_t flt_region_boot;
uint32_t flt_region_fw;
uint32_t flt_region_vpd_nvram;
- uint32_t flt_region_hw_event;
uint32_t flt_region_npiv_conf;
/* Needed for BEACON */
@@ -2737,6 +2743,7 @@ typedef struct scsi_qla_host {
#define OPTROM_SIZE_2322 0x100000
#define OPTROM_SIZE_24XX 0x100000
#define OPTROM_SIZE_25XX 0x200000
+#define OPTROM_SIZE_81XX 0x400000
#include "qla_gbl.h"
#include "qla_dbg.h"
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 0e366a1b44b3..c66036da7d2b 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -113,7 +113,8 @@ int
qla2x00_dfs_setup(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA25XX(ha))
+
+ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
goto out;
if (!ha->fce)
goto out;
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index ee1f1e794c2d..7abb045a0410 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -1215,9 +1215,10 @@ struct qla_fdt_layout {
struct qla_flt_location {
uint8_t sig[4];
- uint32_t start_lo;
- uint32_t start_hi;
- uint16_t unused;
+ uint16_t start_lo;
+ uint16_t start_hi;
+ uint8_t version;
+ uint8_t unused[5];
uint16_t checksum;
};
@@ -1390,4 +1391,291 @@ struct access_chip_rsp_84xx {
uint32_t reserved[12];
};
+
+/* 81XX Support **************************************************************/
+
+#define MBA_DCBX_START 0x8016
+#define MBA_DCBX_COMPLETE 0x8030
+#define MBA_FCF_CONF_ERR 0x8031
+#define MBA_DCBX_PARAM_UPDATE 0x8032
+#define MBA_IDC_COMPLETE 0x8100
+#define MBA_IDC_NOTIFY 0x8101
+#define MBA_IDC_TIME_EXT 0x8102
+
+struct nvram_81xx {
+ /* NVRAM header. */
+ uint8_t id[4];
+ uint16_t nvram_version;
+ uint16_t reserved_0;
+
+ /* Firmware Initialization Control Block. */
+ uint16_t version;
+ uint16_t reserved_1;
+ uint16_t frame_payload_size;
+ uint16_t execution_throttle;
+ uint16_t exchange_count;
+ uint16_t reserved_2;
+
+ uint8_t port_name[WWN_SIZE];
+ uint8_t node_name[WWN_SIZE];
+
+ uint16_t login_retry_count;
+ uint16_t reserved_3;
+ uint16_t interrupt_delay_timer;
+ uint16_t login_timeout;
+
+ uint32_t firmware_options_1;
+ uint32_t firmware_options_2;
+ uint32_t firmware_options_3;
+
+ uint16_t reserved_4[4];
+
+ /* Offset 64. */
+ uint8_t enode_mac[6];
+ uint16_t reserved_5[5];
+
+ /* Offset 80. */
+ uint16_t reserved_6[24];
+
+ /* Offset 128. */
+ uint16_t reserved_7[64];
+
+ /*
+ * BIT 0 = Enable spinup delay
+ * BIT 1 = Disable BIOS
+ * BIT 2 = Enable Memory Map BIOS
+ * BIT 3 = Enable Selectable Boot
+ * BIT 4 = Disable RISC code load
+ * BIT 5 = Disable Serdes
+ * BIT 6 = Opt boot mode
+ * BIT 7 = Interrupt enable
+ *
+ * BIT 8 = EV Control enable
+ * BIT 9 = Enable lip reset
+ * BIT 10 = Enable lip full login
+ * BIT 11 = Enable target reset
+ * BIT 12 = Stop firmware
+ * BIT 13 = Enable nodename option
+ * BIT 14 = Default WWPN valid
+ * BIT 15 = Enable alternate WWN
+ *
+ * BIT 16 = CLP LUN string
+ * BIT 17 = CLP Target string
+ * BIT 18 = CLP BIOS enable string
+ * BIT 19 = CLP Serdes string
+ * BIT 20 = CLP WWPN string
+ * BIT 21 = CLP WWNN string
+ * BIT 22 =
+ * BIT 23 =
+ * BIT 24 = Keep WWPN
+ * BIT 25 = Temp WWPN
+ * BIT 26-31 =
+ */
+ uint32_t host_p;
+
+ uint8_t alternate_port_name[WWN_SIZE];
+ uint8_t alternate_node_name[WWN_SIZE];
+
+ uint8_t boot_port_name[WWN_SIZE];
+ uint16_t boot_lun_number;
+ uint16_t reserved_8;
+
+ uint8_t alt1_boot_port_name[WWN_SIZE];
+ uint16_t alt1_boot_lun_number;
+ uint16_t reserved_9;
+
+ uint8_t alt2_boot_port_name[WWN_SIZE];
+ uint16_t alt2_boot_lun_number;
+ uint16_t reserved_10;
+
+ uint8_t alt3_boot_port_name[WWN_SIZE];
+ uint16_t alt3_boot_lun_number;
+ uint16_t reserved_11;
+
+ /*
+ * BIT 0 = Selective Login
+ * BIT 1 = Alt-Boot Enable
+ * BIT 2 = Reserved
+ * BIT 3 = Boot Order List
+ * BIT 4 = Reserved
+ * BIT 5 = Selective LUN
+ * BIT 6 = Reserved
+ * BIT 7-31 =
+ */
+ uint32_t efi_parameters;
+
+ uint8_t reset_delay;
+ uint8_t reserved_12;
+ uint16_t reserved_13;
+
+ uint16_t boot_id_number;
+ uint16_t reserved_14;
+
+ uint16_t max_luns_per_target;
+ uint16_t reserved_15;
+
+ uint16_t port_down_retry_count;
+ uint16_t link_down_timeout;
+
+ /* FCode parameters. */
+ uint16_t fcode_parameter;
+
+ uint16_t reserved_16[3];
+
+ /* Offset 352. */
+ uint8_t reserved_17[4];
+ uint16_t reserved_18[5];
+ uint8_t reserved_19[2];
+ uint16_t reserved_20[8];
+
+ /* Offset 384. */
+ uint8_t reserved_21[16];
+ uint16_t reserved_22[8];
+
+ /* Offset 416. */
+ uint16_t reserved_23[32];
+
+ /* Offset 480. */
+ uint8_t model_name[16];
+
+ /* Offset 496. */
+ uint16_t feature_mask_l;
+ uint16_t feature_mask_h;
+ uint16_t reserved_24[2];
+
+ uint16_t subsystem_vendor_id;
+ uint16_t subsystem_device_id;
+
+ uint32_t checksum;
+};
+
+/*
+ * ISP Initialization Control Block.
+ * Little endian except where noted.
+ */
+#define ICB_VERSION 1
+struct init_cb_81xx {
+ uint16_t version;
+ uint16_t reserved_1;
+
+ uint16_t frame_payload_size;
+ uint16_t execution_throttle;
+ uint16_t exchange_count;
+
+ uint16_t reserved_2;
+
+ uint8_t port_name[WWN_SIZE]; /* Big endian. */
+ uint8_t node_name[WWN_SIZE]; /* Big endian. */
+
+ uint16_t response_q_inpointer;
+ uint16_t request_q_outpointer;
+
+ uint16_t login_retry_count;
+
+ uint16_t prio_request_q_outpointer;
+
+ uint16_t response_q_length;
+ uint16_t request_q_length;
+
+ uint16_t reserved_3;
+
+ uint16_t prio_request_q_length;
+
+ uint32_t request_q_address[2];
+ uint32_t response_q_address[2];
+ uint32_t prio_request_q_address[2];
+
+ uint8_t reserved_4[8];
+
+ uint16_t atio_q_inpointer;
+ uint16_t atio_q_length;
+ uint32_t atio_q_address[2];
+
+ uint16_t interrupt_delay_timer; /* 100us increments. */
+ uint16_t login_timeout;
+
+ /*
+ * BIT 0-3 = Reserved
+ * BIT 4 = Enable Target Mode
+ * BIT 5 = Disable Initiator Mode
+ * BIT 6 = Reserved
+ * BIT 7 = Reserved
+ *
+ * BIT 8-13 = Reserved
+ * BIT 14 = Node Name Option
+ * BIT 15-31 = Reserved
+ */
+ uint32_t firmware_options_1;
+
+ /*
+ * BIT 0 = Operation Mode bit 0
+ * BIT 1 = Operation Mode bit 1
+ * BIT 2 = Operation Mode bit 2
+ * BIT 3 = Operation Mode bit 3
+ * BIT 4-7 = Reserved
+ *
+ * BIT 8 = Enable Class 2
+ * BIT 9 = Enable ACK0
+ * BIT 10 = Reserved
+ * BIT 11 = Enable FC-SP Security
+ * BIT 12 = FC Tape Enable
+ * BIT 13 = Reserved
+ * BIT 14 = Enable Target PRLI Control
+ * BIT 15-31 = Reserved
+ */
+ uint32_t firmware_options_2;
+
+ /*
+ * BIT 0-3 = Reserved
+ * BIT 4 = FCP RSP Payload bit 0
+ * BIT 5 = FCP RSP Payload bit 1
+ * BIT 6 = Enable Receive Out-of-Order data frame handling
+ * BIT 7 = Reserved
+ *
+ * BIT 8 = Reserved
+ * BIT 9 = Enable Out-of-Order FCP_XFER_RDY relative offset handling
+ * BIT 10-16 = Reserved
+ * BIT 17 = Enable multiple FCFs
+ * BIT 18-20 = MAC addressing mode
+ * BIT 21-25 = Ethernet data rate
+ * BIT 26 = Enable ethernet header rx IOCB for ATIO q
+ * BIT 27 = Enable ethernet header rx IOCB for response q
+ * BIT 28 = SPMA selection bit 0
+ * BIT 28 = SPMA selection bit 1
+ * BIT 30-31 = Reserved
+ */
+ uint32_t firmware_options_3;
+
+ uint8_t reserved_5[8];
+
+ uint8_t enode_mac[6];
+
+ uint8_t reserved_6[10];
+};
+
+struct mid_init_cb_81xx {
+ struct init_cb_81xx init_cb;
+
+ uint16_t count;
+ uint16_t options;
+
+ struct mid_conf_entry_24xx entries[MAX_MULTI_ID_FABRIC];
+};
+
+#define FARX_ACCESS_FLASH_CONF_81XX 0x7FFD0000
+#define FARX_ACCESS_FLASH_DATA_81XX 0x7F800000
+
+/* 81XX Flash locations -- occupies second 2MB region. */
+#define FA_BOOT_CODE_ADDR_81 0x80000
+#define FA_RISC_CODE_ADDR_81 0xA0000
+#define FA_FW_AREA_ADDR_81 0xC0000
+#define FA_VPD_NVRAM_ADDR_81 0xD0000
+#define FA_FEATURE_ADDR_81 0xD4000
+#define FA_FLASH_DESCR_ADDR_81 0xD8000
+#define FA_FLASH_LAYOUT_ADDR_81 0xD8400
+#define FA_HW_EVENT0_ADDR_81 0xDC000
+#define FA_HW_EVENT1_ADDR_81 0xDC400
+#define FA_NPIV_CONF0_ADDR_81 0xD1000
+#define FA_NPIV_CONF1_ADDR_81 0xD2000
+
#endif
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 0011e31205db..ba4913353752 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -28,8 +28,10 @@ extern void qla2x00_reset_adapter(struct scsi_qla_host *);
extern void qla24xx_reset_adapter(struct scsi_qla_host *);
extern int qla2x00_nvram_config(struct scsi_qla_host *);
extern int qla24xx_nvram_config(struct scsi_qla_host *);
+extern int qla81xx_nvram_config(struct scsi_qla_host *);
extern void qla2x00_update_fw_options(struct scsi_qla_host *);
extern void qla24xx_update_fw_options(scsi_qla_host_t *);
+extern void qla81xx_update_fw_options(scsi_qla_host_t *);
extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *);
extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *);
@@ -69,8 +71,6 @@ extern int qla2x00_loop_reset(scsi_qla_host_t *);
extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum
fc_host_event_code, u32);
-extern int qla2x00_post_hwe_work(struct scsi_qla_host *, uint16_t , uint16_t,
- uint16_t, uint16_t);
extern void qla2x00_abort_fcport_cmds(fc_port_t *);
extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *,
@@ -143,7 +143,7 @@ qla2x00_execute_fw(scsi_qla_host_t *, uint32_t);
extern void
qla2x00_get_fw_version(scsi_qla_host_t *, uint16_t *,
- uint16_t *, uint16_t *, uint16_t *, uint32_t *);
+ uint16_t *, uint16_t *, uint16_t *, uint32_t *, uint8_t *, uint32_t *);
extern int
qla2x00_get_fw_options(scsi_qla_host_t *, uint16_t *);
@@ -317,9 +317,6 @@ extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *,
extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *);
extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *);
-extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t,
- uint16_t, uint16_t);
-
extern int qla2xxx_get_flash_info(scsi_qla_host_t *);
extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t);
@@ -332,6 +329,7 @@ extern void qla2100_fw_dump(scsi_qla_host_t *, int);
extern void qla2300_fw_dump(scsi_qla_host_t *, int);
extern void qla24xx_fw_dump(scsi_qla_host_t *, int);
extern void qla25xx_fw_dump(scsi_qla_host_t *, int);
+extern void qla81xx_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);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 0a6f72973996..557f58d5bf88 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -1535,7 +1535,10 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED);
eiter->len = __constant_cpu_to_be16(4 + 4);
- if (IS_QLA25XX(ha))
+ if (IS_QLA81XX(ha))
+ eiter->a.sup_speed = __constant_cpu_to_be32(
+ FDMI_PORT_SPEED_10GB);
+ else if (IS_QLA25XX(ha))
eiter->a.sup_speed = __constant_cpu_to_be32(
FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB|
FDMI_PORT_SPEED_4GB|FDMI_PORT_SPEED_8GB);
@@ -1575,6 +1578,10 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
eiter->a.cur_speed =
__constant_cpu_to_be32(FDMI_PORT_SPEED_8GB);
break;
+ case PORT_SPEED_10GB:
+ eiter->a.cur_speed =
+ __constant_cpu_to_be32(FDMI_PORT_SPEED_10GB);
+ break;
default:
eiter->a.cur_speed =
__constant_cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN);
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 52ed56ecf195..9ad4d0968e5c 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -552,10 +552,6 @@ qla24xx_reset_risc(scsi_qla_host_t *vha)
d2 = RD_REG_DWORD(&reg->ctrl_status);
barrier();
}
- if (cnt == 0 || hw_evt)
- qla2xxx_hw_event_log(vha, HW_EVENT_RESET_ERR,
- RD_REG_WORD(&reg->mailbox1), RD_REG_WORD(&reg->mailbox2),
- RD_REG_WORD(&reg->mailbox3));
WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
RD_REG_DWORD(&reg->hccr);
@@ -574,6 +570,9 @@ qla24xx_reset_risc(scsi_qla_host_t *vha)
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if (IS_NOPOLLING_TYPE(ha))
+ ha->isp_ops->enable_intrs(ha);
}
/**
@@ -779,16 +778,19 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
mem_size = (ha->fw_memory_size - 0x11000 + 1) *
sizeof(uint16_t);
} else if (IS_FWI2_CAPABLE(ha)) {
- fixed_size = IS_QLA25XX(ha) ?
- offsetof(struct qla25xx_fw_dump, ext_mem) :
- offsetof(struct qla24xx_fw_dump, ext_mem);
+ if (IS_QLA81XX(ha))
+ fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem);
+ else if (IS_QLA25XX(ha))
+ fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem);
+ else
+ fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
mem_size = (ha->fw_memory_size - 0x100000 + 1) *
sizeof(uint32_t);
if (ha->mqenable)
mq_size = sizeof(struct qla2xxx_mq_chain);
/* Allocate memory for Fibre Channel Event Buffer. */
- if (!IS_QLA25XX(ha))
+ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
goto try_eft;
tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
@@ -851,7 +853,9 @@ cont_alloc:
dump_size = offsetof(struct qla2xxx_fw_dump, isp);
dump_size += fixed_size + mem_size + req_q_size + rsp_q_size +
- mq_size + eft_size + fce_size;
+ eft_size;
+ ha->chain_offset = dump_size;
+ dump_size += mq_size + fce_size;
ha->fw_dump = vmalloc(dump_size);
if (!ha->fw_dump) {
@@ -987,7 +991,8 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
&ha->fw_major_version,
&ha->fw_minor_version,
&ha->fw_subminor_version,
- &ha->fw_attributes, &ha->fw_memory_size);
+ &ha->fw_attributes, &ha->fw_memory_size,
+ ha->mpi_version, &ha->mpi_capabilities);
ha->flags.npiv_supported = 0;
if (IS_QLA2XXX_MIDTYPE(ha) &&
(ha->fw_attributes & BIT_2)) {
@@ -1253,35 +1258,48 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
{
int rval;
unsigned long flags = 0;
- int cnt;
+ int cnt, que;
struct qla_hw_data *ha = vha->hw;
- struct req_que *req = ha->req_q_map[0];
- struct rsp_que *rsp = ha->rsp_q_map[0];
+ struct req_que *req;
+ struct rsp_que *rsp;
+ struct scsi_qla_host *vp;
struct mid_init_cb_24xx *mid_init_cb =
(struct mid_init_cb_24xx *) ha->init_cb;
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Clear outstanding commands array. */
- for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
- req->outstanding_cmds[cnt] = NULL;
+ for (que = 0; que < ha->max_queues; que++) {
+ req = ha->req_q_map[que];
+ if (!req)
+ continue;
+ for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
+ req->outstanding_cmds[cnt] = NULL;
- req->current_outstanding_cmd = 0;
+ req->current_outstanding_cmd = 0;
- /* Clear RSCN queue. */
- vha->rscn_in_ptr = 0;
- vha->rscn_out_ptr = 0;
+ /* Initialize firmware. */
+ req->ring_ptr = req->ring;
+ req->ring_index = 0;
+ req->cnt = req->length;
+ }
- /* Initialize firmware. */
- req->ring_ptr = req->ring;
- req->ring_index = 0;
- req->cnt = req->length;
- rsp->ring_ptr = rsp->ring;
- rsp->ring_index = 0;
+ for (que = 0; que < ha->max_queues; que++) {
+ rsp = ha->rsp_q_map[que];
+ if (!rsp)
+ continue;
+ rsp->ring_ptr = rsp->ring;
+ rsp->ring_index = 0;
- /* Initialize response queue entries */
- qla2x00_init_response_q_entries(rsp);
+ /* Initialize response queue entries */
+ qla2x00_init_response_q_entries(rsp);
+ }
+ /* Clear RSCN queue. */
+ list_for_each_entry(vp, &ha->vp_list, list) {
+ vp->rscn_in_ptr = 0;
+ vp->rscn_out_ptr = 0;
+ }
ha->isp_ops->config_rings(vha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -1665,10 +1683,6 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
"invalid -- WWPN) defaults.\n");
- if (chksum)
- qla2xxx_hw_event_log(vha, HW_EVENT_NVRAM_CHKSUM_ERR, 0,
- MSW(chksum), LSW(chksum));
-
/*
* Set default initialization control block.
*/
@@ -3211,8 +3225,8 @@ qla2x00_loop_resync(scsi_qla_host_t *vha)
int rval = QLA_SUCCESS;
uint32_t wait_time;
struct qla_hw_data *ha = vha->hw;
- struct req_que *req = ha->req_q_map[0];
- struct rsp_que *rsp = ha->rsp_q_map[0];
+ struct req_que *req = ha->req_q_map[vha->req_ques[0]];
+ struct rsp_que *rsp = req->rsp;
atomic_set(&vha->loop_state, LOOP_UPDATE);
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
@@ -3491,6 +3505,7 @@ qla25xx_init_queues(struct qla_hw_data *ha)
}
req = ha->req_q_map[i];
if (req) {
+ /* Clear outstanding commands array. */
req->options &= ~BIT_0;
ret = qla25xx_init_req_que(base_vha, req, req->options);
if (ret != QLA_SUCCESS)
@@ -3499,7 +3514,7 @@ qla25xx_init_queues(struct qla_hw_data *ha)
req->id));
else
DEBUG2_17(printk(KERN_WARNING
- "%s Rsp que:%d inited\n", __func__,
+ "%s Req que:%d inited\n", __func__,
req->id));
}
}
@@ -4150,8 +4165,8 @@ qla24xx_configure_vhba(scsi_qla_host_t *vha)
uint16_t mb[MAILBOX_REGISTER_COUNT];
struct qla_hw_data *ha = vha->hw;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
- struct req_que *req = ha->req_q_map[0];
- struct rsp_que *rsp = ha->rsp_q_map[0];
+ struct req_que *req = ha->req_q_map[vha->req_ques[0]];
+ struct rsp_que *rsp = req->rsp;
if (!vha->vp_idx)
return -EINVAL;
@@ -4255,3 +4270,269 @@ qla84xx_init_chip(scsi_qla_host_t *vha)
return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED:
QLA_SUCCESS;
}
+
+/* 81XX Support **************************************************************/
+
+int
+qla81xx_nvram_config(scsi_qla_host_t *vha)
+{
+ int rval;
+ struct init_cb_81xx *icb;
+ struct nvram_81xx *nv;
+ uint32_t *dptr;
+ uint8_t *dptr1, *dptr2;
+ uint32_t chksum;
+ uint16_t cnt;
+ struct qla_hw_data *ha = vha->hw;
+
+ rval = QLA_SUCCESS;
+ icb = (struct init_cb_81xx *)ha->init_cb;
+ nv = ha->nvram;
+
+ /* Determine NVRAM starting address. */
+ ha->nvram_size = sizeof(struct nvram_81xx);
+ ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
+ ha->vpd_size = FA_NVRAM_VPD_SIZE;
+ ha->vpd_base = FA_NVRAM_VPD0_ADDR;
+ if (PCI_FUNC(ha->pdev->devfn) & 1) {
+ ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
+ ha->vpd_base = FA_NVRAM_VPD1_ADDR;
+ }
+
+ /* Get VPD data into cache */
+ ha->vpd = ha->nvram + VPD_OFFSET;
+ ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd,
+ ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4);
+
+ /* Get NVRAM data into cache and calculate checksum. */
+ dptr = (uint32_t *)nv;
+ ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base,
+ ha->nvram_size);
+ for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
+ chksum += le32_to_cpu(*dptr++);
+
+ DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
+ DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
+
+ /* Bad NVRAM data, set defaults parameters. */
+ if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
+ || nv->id[3] != ' ' ||
+ nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
+ /* Reset NVRAM data. */
+ qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
+ "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
+ le16_to_cpu(nv->nvram_version));
+ qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
+ "invalid -- WWPN) defaults.\n");
+
+ /*
+ * Set default initialization control block.
+ */
+ memset(nv, 0, ha->nvram_size);
+ nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
+ nv->version = __constant_cpu_to_le16(ICB_VERSION);
+ nv->frame_payload_size = __constant_cpu_to_le16(2048);
+ nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
+ nv->exchange_count = __constant_cpu_to_le16(0);
+ nv->port_name[0] = 0x21;
+ nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
+ nv->port_name[2] = 0x00;
+ nv->port_name[3] = 0xe0;
+ nv->port_name[4] = 0x8b;
+ nv->port_name[5] = 0x1c;
+ nv->port_name[6] = 0x55;
+ nv->port_name[7] = 0x86;
+ nv->node_name[0] = 0x20;
+ nv->node_name[1] = 0x00;
+ nv->node_name[2] = 0x00;
+ nv->node_name[3] = 0xe0;
+ nv->node_name[4] = 0x8b;
+ nv->node_name[5] = 0x1c;
+ nv->node_name[6] = 0x55;
+ nv->node_name[7] = 0x86;
+ nv->login_retry_count = __constant_cpu_to_le16(8);
+ nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
+ nv->login_timeout = __constant_cpu_to_le16(0);
+ nv->firmware_options_1 =
+ __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
+ nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
+ nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
+ nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
+ nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
+ nv->efi_parameters = __constant_cpu_to_le32(0);
+ nv->reset_delay = 5;
+ nv->max_luns_per_target = __constant_cpu_to_le16(128);
+ nv->port_down_retry_count = __constant_cpu_to_le16(30);
+ nv->link_down_timeout = __constant_cpu_to_le16(30);
+ nv->enode_mac[0] = 0x01;
+ nv->enode_mac[1] = 0x02;
+ nv->enode_mac[2] = 0x03;
+ nv->enode_mac[3] = 0x04;
+ nv->enode_mac[4] = 0x05;
+ nv->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn);
+
+ rval = 1;
+ }
+
+ /* Reset Initialization control block */
+ memset(icb, 0, sizeof(struct init_cb_81xx));
+
+ /* Copy 1st segment. */
+ dptr1 = (uint8_t *)icb;
+ dptr2 = (uint8_t *)&nv->version;
+ cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version;
+ while (cnt--)
+ *dptr1++ = *dptr2++;
+
+ icb->login_retry_count = nv->login_retry_count;
+
+ /* Copy 2nd segment. */
+ dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
+ dptr2 = (uint8_t *)&nv->interrupt_delay_timer;
+ cnt = (uint8_t *)&icb->reserved_5 -
+ (uint8_t *)&icb->interrupt_delay_timer;
+ while (cnt--)
+ *dptr1++ = *dptr2++;
+
+ memcpy(icb->enode_mac, nv->enode_mac, sizeof(icb->enode_mac));
+ /* Some boards (with valid NVRAMs) still have NULL enode_mac!! */
+ if (!memcmp(icb->enode_mac, "\0\0\0\0\0\0", sizeof(icb->enode_mac))) {
+ icb->enode_mac[0] = 0x01;
+ icb->enode_mac[1] = 0x02;
+ icb->enode_mac[2] = 0x03;
+ icb->enode_mac[3] = 0x04;
+ icb->enode_mac[4] = 0x05;
+ icb->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn);
+ }
+
+ /*
+ * Setup driver NVRAM options.
+ */
+ qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
+ "QLE81XX");
+
+ /* Use alternate WWN? */
+ if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
+ memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
+ memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
+ }
+
+ /* Prepare nodename */
+ if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) {
+ /*
+ * Firmware will apply the following mask if the nodename was
+ * not provided.
+ */
+ memcpy(icb->node_name, icb->port_name, WWN_SIZE);
+ icb->node_name[0] &= 0xF0;
+ }
+
+ /* Set host adapter parameters. */
+ ha->flags.disable_risc_code_load = 0;
+ ha->flags.enable_lip_reset = 0;
+ ha->flags.enable_lip_full_login =
+ le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
+ ha->flags.enable_target_reset =
+ le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
+ ha->flags.enable_led_scheme = 0;
+ ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
+
+ ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
+ (BIT_6 | BIT_5 | BIT_4)) >> 4;
+
+ /* save HBA serial number */
+ ha->serial0 = icb->port_name[5];
+ ha->serial1 = icb->port_name[6];
+ ha->serial2 = icb->port_name[7];
+ memcpy(vha->node_name, icb->node_name, WWN_SIZE);
+ memcpy(vha->port_name, icb->port_name, WWN_SIZE);
+
+ icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
+
+ ha->retry_count = le16_to_cpu(nv->login_retry_count);
+
+ /* Set minimum login_timeout to 4 seconds. */
+ if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout)
+ nv->login_timeout = cpu_to_le16(ql2xlogintimeout);
+ if (le16_to_cpu(nv->login_timeout) < 4)
+ nv->login_timeout = __constant_cpu_to_le16(4);
+ ha->login_timeout = le16_to_cpu(nv->login_timeout);
+ icb->login_timeout = nv->login_timeout;
+
+ /* Set minimum RATOV to 100 tenths of a second. */
+ ha->r_a_tov = 100;
+
+ ha->loop_reset_delay = nv->reset_delay;
+
+ /* Link Down Timeout = 0:
+ *
+ * When Port Down timer expires we will start returning
+ * I/O's to OS with "DID_NO_CONNECT".
+ *
+ * Link Down Timeout != 0:
+ *
+ * The driver waits for the link to come up after link down
+ * before returning I/Os to OS with "DID_NO_CONNECT".
+ */
+ if (le16_to_cpu(nv->link_down_timeout) == 0) {
+ ha->loop_down_abort_time =
+ (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
+ } else {
+ ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout);
+ ha->loop_down_abort_time =
+ (LOOP_DOWN_TIME - ha->link_down_timeout);
+ }
+
+ /* Need enough time to try and get the port back. */
+ ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count);
+ if (qlport_down_retry)
+ ha->port_down_retry_count = qlport_down_retry;
+
+ /* Set login_retry_count */
+ ha->login_retry_count = le16_to_cpu(nv->login_retry_count);
+ if (ha->port_down_retry_count ==
+ le16_to_cpu(nv->port_down_retry_count) &&
+ ha->port_down_retry_count > 3)
+ ha->login_retry_count = ha->port_down_retry_count;
+ else if (ha->port_down_retry_count > (int)ha->login_retry_count)
+ ha->login_retry_count = ha->port_down_retry_count;
+ if (ql2xloginretrycount)
+ ha->login_retry_count = ql2xloginretrycount;
+
+ /* Enable ZIO. */
+ if (!vha->flags.init_done) {
+ ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
+ (BIT_3 | BIT_2 | BIT_1 | BIT_0);
+ ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
+ le16_to_cpu(icb->interrupt_delay_timer): 2;
+ }
+ icb->firmware_options_2 &= __constant_cpu_to_le32(
+ ~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
+ vha->flags.process_response_queue = 0;
+ if (ha->zio_mode != QLA_ZIO_DISABLED) {
+ ha->zio_mode = QLA_ZIO_MODE_6;
+
+ DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
+ "(%d us).\n", vha->host_no, ha->zio_mode,
+ ha->zio_timer * 100));
+ qla_printk(KERN_INFO, ha,
+ "ZIO mode %d enabled; timer delay (%d us).\n",
+ ha->zio_mode, ha->zio_timer * 100);
+
+ icb->firmware_options_2 |= cpu_to_le32(
+ (uint32_t)ha->zio_mode);
+ icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
+ vha->flags.process_response_queue = 1;
+ }
+
+ if (rval) {
+ DEBUG2_3(printk(KERN_WARNING
+ "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
+ }
+ return (rval);
+}
+
+void
+qla81xx_update_fw_options(scsi_qla_host_t *ha)
+{
+}
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 5bedc9d05942..2258152b1f41 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -173,7 +173,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
return;
}
- vha = sp->vha;
+ vha = sp->fcport->vha;
req = sp->que;
cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
@@ -234,7 +234,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
return;
}
- vha = sp->vha;
+ vha = sp->fcport->vha;
req = sp->que;
cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp));
@@ -294,7 +294,7 @@ qla2x00_start_scsi(srb_t *sp)
/* Setup device pointers. */
ret = 0;
- vha = sp->vha;
+ vha = sp->fcport->vha;
ha = vha->hw;
reg = &ha->iobase->isp;
cmd = sp->cmd;
@@ -353,7 +353,6 @@ qla2x00_start_scsi(srb_t *sp)
/* Build command packet */
req->current_outstanding_cmd = handle;
req->outstanding_cmds[handle] = sp;
- sp->vha = vha;
sp->que = req;
sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
req->cnt -= req_cnt;
@@ -656,7 +655,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
return;
}
- vha = sp->vha;
+ vha = sp->fcport->vha;
req = sp->que;
/* Set transfer direction */
@@ -723,7 +722,7 @@ qla24xx_start_scsi(srb_t *sp)
struct req_que *req = NULL;
struct rsp_que *rsp = NULL;
struct scsi_cmnd *cmd = sp->cmd;
- struct scsi_qla_host *vha = sp->vha;
+ struct scsi_qla_host *vha = sp->fcport->vha;
struct qla_hw_data *ha = vha->hw;
uint16_t que_id;
@@ -791,7 +790,6 @@ qla24xx_start_scsi(srb_t *sp)
/* Build command packet. */
req->current_outstanding_cmd = handle;
req->outstanding_cmds[handle] = sp;
- sp->vha = vha;
sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
req->cnt -= req_cnt;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index d5fb79a88001..789fc576f222 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -275,7 +275,7 @@ void
qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
{
#define LS_UNKNOWN 2
- static char *link_speeds[5] = { "1", "2", "?", "4", "8" };
+ static char *link_speeds[] = { "1", "2", "?", "4", "8", "10" };
char *link_speed;
uint16_t handle_cnt;
uint16_t cnt;
@@ -288,6 +288,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
/* Setup to process RIO completion. */
handle_cnt = 0;
+ if (IS_QLA81XX(ha))
+ goto skip_rio;
switch (mb[0]) {
case MBA_SCSI_COMPLETION:
handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
@@ -339,7 +341,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
default:
break;
}
-
+skip_rio:
switch (mb[0]) {
case MBA_SCSI_COMPLETION: /* Fast Post */
if (!vha->flags.online)
@@ -362,7 +364,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
"ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
mb[1], mb[2], mb[3]);
- qla2x00_post_hwe_work(vha, mb[0], mb[1], mb[2], mb[3]);
ha->isp_ops->fw_dump(vha, 1);
if (IS_FWI2_CAPABLE(ha)) {
@@ -387,7 +388,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
vha->host_no));
qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n");
- qla2x00_post_hwe_work(vha, mb[0], mb[1], mb[2], mb[3]);
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
break;
@@ -396,7 +396,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
vha->host_no));
qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n");
- qla2x00_post_hwe_work(vha, mb[0], mb[1], mb[2], mb[3]);
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
break;
@@ -436,6 +435,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
link_speed = link_speeds[LS_UNKNOWN];
if (mb[1] < 5)
link_speed = link_speeds[mb[1]];
+ else if (mb[1] == 0x13)
+ link_speed = link_speeds[5];
ha->link_data_rate = mb[1];
}
@@ -495,12 +496,17 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]);
break;
+ /* case MBA_DCBX_COMPLETE: */
case MBA_POINT_TO_POINT: /* Point-to-Point */
if (IS_QLA2100(ha))
break;
- DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE received.\n",
- vha->host_no));
+ if (IS_QLA81XX(ha))
+ DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x "
+ "%04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+ else
+ DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE "
+ "received.\n", vha->host_no));
/*
* Until there's a transition from loop down to loop up, treat
@@ -641,10 +647,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
/* case MBA_RIO_RESPONSE: */
case MBA_ZIO_RESPONSE:
- DEBUG2(printk("scsi(%ld): [R|Z]IO update completion.\n",
- vha->host_no));
- DEBUG(printk(KERN_INFO
- "scsi(%ld): [R|Z]IO update completion.\n",
+ DEBUG3(printk("scsi(%ld): [R|Z]IO update completion.\n",
vha->host_no));
if (IS_FWI2_CAPABLE(ha))
@@ -698,6 +701,35 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
}
spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
break;
+ case MBA_DCBX_START:
+ DEBUG2(printk("scsi(%ld): DCBX Started -- %04x %04x %04x\n",
+ vha->host_no, mb[1], mb[2], mb[3]));
+ break;
+ case MBA_DCBX_PARAM_UPDATE:
+ DEBUG2(printk("scsi(%ld): DCBX Parameters Updated -- "
+ "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+ break;
+ case MBA_FCF_CONF_ERR:
+ DEBUG2(printk("scsi(%ld): FCF Configuration Error -- "
+ "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
+ break;
+ case MBA_IDC_COMPLETE:
+ DEBUG2(printk("scsi(%ld): Inter-Driver Commucation "
+ "Complete -- %04x %04x %04x\n", vha->host_no, mb[1], mb[2],
+ mb[3]));
+ break;
+ case MBA_IDC_NOTIFY:
+ DEBUG2(printk("scsi(%ld): Inter-Driver Commucation "
+ "Request Notification -- %04x %04x %04x\n", vha->host_no,
+ mb[1], mb[2], mb[3]));
+ /**** Mailbox registers 4 - 7 valid!!! */
+ break;
+ case MBA_IDC_TIME_EXT:
+ DEBUG2(printk("scsi(%ld): Inter-Driver Commucation "
+ "Time Extension -- %04x %04x %04x\n", vha->host_no, mb[1],
+ mb[2], mb[3]));
+ /**** Mailbox registers 4 - 7 valid!!! */
+ break;
}
if (!vha->vp_idx && ha->num_vhosts)
@@ -1510,7 +1542,7 @@ qla2xxx_check_risc_status(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
- if (!IS_QLA25XX(ha))
+ if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
return;
rval = QLA_SUCCESS;
@@ -1590,12 +1622,6 @@ qla24xx_intr_handler(int irq, void *dev_id)
if (pci_channel_offline(ha->pdev))
break;
- if (ha->hw_event_pause_errors == 0)
- qla2x00_post_hwe_work(vha, HW_EVENT_PARITY_ERR,
- 0, MSW(stat), LSW(stat));
- else if (ha->hw_event_pause_errors < 0xffffffff)
- ha->hw_event_pause_errors++;
-
hccr = RD_REG_DWORD(&reg->hccr);
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
@@ -1740,12 +1766,6 @@ qla24xx_msix_default(int irq, void *dev_id)
if (pci_channel_offline(ha->pdev))
break;
- if (ha->hw_event_pause_errors == 0)
- qla2x00_post_hwe_work(vha, HW_EVENT_PARITY_ERR,
- 0, MSW(stat), LSW(stat));
- else if (ha->hw_event_pause_errors < 0xffffffff)
- ha->hw_event_pause_errors++;
-
hccr = RD_REG_DWORD(&reg->hccr);
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
@@ -1944,7 +1964,8 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
device_reg_t __iomem *reg = ha->iobase;
/* If possible, enable MSI-X. */
- if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha))
+ if (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
+ !IS_QLA8432(ha) && !IS_QLA8001(ha))
goto skip_msix;
if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX ||
@@ -1979,7 +2000,8 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
"MSI-X: Falling back-to INTa mode -- %d.\n", ret);
skip_msix:
- if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha))
+ if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
+ !IS_QLA8001(ha))
goto skip_msi;
ret = pci_enable_msi(ha->pdev);
@@ -2000,6 +2022,12 @@ skip_msi:
ha->flags.inta_enabled = 1;
clear_risc_ints:
+ /*
+ * FIXME: Noted that 8014s were being dropped during NK testing.
+ * Timing deltas during MSI-X/INTa transitions?
+ */
+ if (IS_QLA81XX(ha))
+ goto fail;
spin_lock_irq(&ha->hardware_lock);
if (IS_FWI2_CAPABLE(ha)) {
WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
@@ -2044,7 +2072,7 @@ qla2x00_get_rsp_host(struct rsp_que *rsp)
if (pkt && pkt->handle < MAX_OUTSTANDING_COMMANDS) {
sp = req->outstanding_cmds[pkt->handle];
if (sp)
- vha = sp->vha;
+ vha = sp->fcport->vha;
}
}
if (!vha)
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index a99976f5fabd..db4df45234a5 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -123,8 +123,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
/* Wait for mbx cmd completion until timeout */
- if (!abort_active && io_lock_on) {
-
+ if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) {
set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
if (IS_FWI2_CAPABLE(ha))
@@ -218,7 +217,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
/* Clean up */
ha->mcp = NULL;
- if (abort_active || !io_lock_on) {
+ if ((abort_active || !io_lock_on) && !IS_NOPOLLING_TYPE(ha)) {
DEBUG11(printk("%s(%ld): checking for additional resp "
"interrupt.\n", __func__, base_vha->host_no));
@@ -412,7 +411,8 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
*/
void
qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor,
- uint16_t *subminor, uint16_t *attributes, uint32_t *memory)
+ uint16_t *subminor, uint16_t *attributes, uint32_t *memory, uint8_t *mpi,
+ uint32_t *mpi_caps)
{
int rval;
mbx_cmd_t mc;
@@ -423,6 +423,8 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor,
mcp->mb[0] = MBC_GET_FIRMWARE_VERSION;
mcp->out_mb = MBX_0;
mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ if (IS_QLA81XX(vha->hw))
+ mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;
mcp->flags = 0;
mcp->tov = MBX_TOV_SECONDS;
rval = qla2x00_mailbox_command(vha, mcp);
@@ -436,6 +438,13 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor,
*memory = 0x1FFFF; /* Defaults to 128KB. */
else
*memory = (mcp->mb[5] << 16) | mcp->mb[4];
+ if (IS_QLA81XX(vha->hw)) {
+ mpi[0] = mcp->mb[10] >> 8;
+ mpi[1] = mcp->mb[10] & 0xff;
+ mpi[2] = mcp->mb[11] >> 8;
+ mpi[3] = mcp->mb[11] & 0xff;
+ *mpi_caps = (mcp->mb[12] << 16) | mcp->mb[13];
+ }
if (rval != QLA_SUCCESS) {
/*EMPTY*/
@@ -568,7 +577,6 @@ int
qla2x00_mbx_reg_test(scsi_qla_host_t *vha)
{
int rval;
- struct qla_hw_data *ha = vha->hw;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
@@ -595,14 +603,6 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *vha)
if (mcp->mb[5] != 0xA5A5 || mcp->mb[6] != 0x5A5A ||
mcp->mb[7] != 0x2525)
rval = QLA_FUNCTION_FAILED;
- if (rval == QLA_FUNCTION_FAILED) {
- struct device_reg_24xx __iomem *reg =
- &ha->iobase->isp24;
-
- qla2xxx_hw_event_log(vha, HW_EVENT_ISP_ERR, 0,
- LSW(RD_REG_DWORD(&reg->hccr)),
- LSW(RD_REG_DWORD(&reg->istatus)));
- }
}
if (rval != QLA_SUCCESS) {
@@ -1363,7 +1363,13 @@ qla2x00_lip_reset(scsi_qla_host_t *vha)
DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
- if (IS_FWI2_CAPABLE(vha->hw)) {
+ if (IS_QLA81XX(vha->hw)) {
+ /* Logout across all FCFs. */
+ mcp->mb[0] = MBC_LIP_FULL_LOGIN;
+ mcp->mb[1] = BIT_1;
+ mcp->mb[2] = 0;
+ mcp->out_mb = MBX_2|MBX_1|MBX_0;
+ } else if (IS_FWI2_CAPABLE(vha->hw)) {
mcp->mb[0] = MBC_LIP_FULL_LOGIN;
mcp->mb[1] = BIT_6;
mcp->mb[2] = 0;
@@ -1853,6 +1859,9 @@ qla2x00_full_login_lip(scsi_qla_host_t *vha)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
+ if (IS_QLA81XX(vha->hw))
+ return QLA_SUCCESS;
+
DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n",
vha->host_no));
@@ -2512,7 +2521,7 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma,
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA25XX(vha->hw))
+ if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
@@ -3155,7 +3164,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp,
mcp->mb[7] = LSW(MSD(rsp->dma));
mcp->mb[5] = rsp->length;
mcp->mb[11] = rsp->vp_idx;
- mcp->mb[14] = rsp->msix->vector;
+ mcp->mb[14] = rsp->msix->entry;
mcp->mb[13] = rsp->rid;
reg = (struct device_reg_25xxmq *)((void *)(ha->mqiobase) +
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 386ffeae5b5a..f53179c46423 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -614,8 +614,10 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
req->vp_idx = vp_idx;
req->qos = qos;
- if (ha->rsp_q_map[rsp_que])
+ if (ha->rsp_q_map[rsp_que]) {
req->rsp = ha->rsp_q_map[rsp_que];
+ req->rsp->req = req;
+ }
/* Use alternate PCI bus number */
if (MSB(req->rid))
options |= BIT_4;
@@ -627,6 +629,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
req->ring_index = 0;
req->cnt = req->length;
req->id = que_id;
+ req->max_q_depth = ha->req_q_map[0]->max_q_depth;
mutex_unlock(&ha->vport_lock);
ret = qla25xx_init_req_que(base_vha, req, options);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 8ea927788b3f..cf32653fe01a 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -404,26 +404,9 @@ static char *
qla24xx_fw_version_str(struct scsi_qla_host *vha, char *str)
{
struct qla_hw_data *ha = vha->hw;
- sprintf(str, "%d.%02d.%02d ", ha->fw_major_version,
- ha->fw_minor_version,
- ha->fw_subminor_version);
- if (ha->fw_attributes & BIT_0)
- strcat(str, "[Class 2] ");
- if (ha->fw_attributes & BIT_1)
- strcat(str, "[IP] ");
- if (ha->fw_attributes & BIT_2)
- strcat(str, "[Multi-ID] ");
- if (ha->fw_attributes & BIT_3)
- strcat(str, "[SB-2] ");
- if (ha->fw_attributes & BIT_4)
- strcat(str, "[T10 CRC] ");
- if (ha->fw_attributes & BIT_5)
- strcat(str, "[VI] ");
- if (ha->fw_attributes & BIT_10)
- strcat(str, "[84XX] ");
- if (ha->fw_attributes & BIT_13)
- strcat(str, "[Experimental]");
+ sprintf(str, "%d.%02d.%02d (%x)", ha->fw_major_version,
+ ha->fw_minor_version, ha->fw_subminor_version, ha->fw_attributes);
return str;
}
@@ -438,7 +421,6 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
if (!sp)
return sp;
- sp->vha = vha;
sp->fcport = fcport;
sp->cmd = cmd;
sp->que = ha->req_q_map[0];
@@ -1176,13 +1158,13 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
struct req_que *req;
spin_lock_irqsave(&ha->hardware_lock, flags);
- for (que = 0; que < QLA_MAX_HOST_QUES; que++) {
- req = ha->req_q_map[vha->req_ques[que]];
+ for (que = 0; que < ha->max_queues; que++) {
+ req = ha->req_q_map[que];
if (!req)
continue;
for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
sp = req->outstanding_cmds[cnt];
- if (sp && sp->vha == vha) {
+ if (sp && sp->fcport->vha == vha) {
req->outstanding_cmds[cnt] = NULL;
sp->cmd->result = res;
qla2x00_sp_compl(ha, sp);
@@ -1211,7 +1193,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev)
scsi_qla_host_t *vha = shost_priv(sdev->host);
struct qla_hw_data *ha = vha->hw;
struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
- struct req_que *req = ha->req_q_map[0];
+ struct req_que *req = ha->req_q_map[vha->req_ques[0]];
if (sdev->tagged_supported)
scsi_activate_tcq(sdev, req->max_q_depth);
@@ -1329,6 +1311,8 @@ qla24xx_disable_intrs(struct qla_hw_data *ha)
unsigned long flags = 0;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ if (IS_NOPOLLING_TYPE(ha))
+ return;
spin_lock_irqsave(&ha->hardware_lock, flags);
ha->interrupts_on = 0;
WRT_REG_DWORD(&reg->ictrl, 0);
@@ -1488,6 +1472,44 @@ static struct isp_operations qla25xx_isp_ops = {
.rd_req_reg = qla24xx_rd_req_reg,
};
+static struct isp_operations qla81xx_isp_ops = {
+ .pci_config = qla25xx_pci_config,
+ .reset_chip = qla24xx_reset_chip,
+ .chip_diag = qla24xx_chip_diag,
+ .config_rings = qla24xx_config_rings,
+ .reset_adapter = qla24xx_reset_adapter,
+ .nvram_config = qla81xx_nvram_config,
+ .update_fw_options = qla81xx_update_fw_options,
+ .load_risc = qla24xx_load_risc,
+ .pci_info_str = qla24xx_pci_info_str,
+ .fw_version_str = qla24xx_fw_version_str,
+ .intr_handler = qla24xx_intr_handler,
+ .enable_intrs = qla24xx_enable_intrs,
+ .disable_intrs = qla24xx_disable_intrs,
+ .abort_command = qla24xx_abort_command,
+ .target_reset = qla24xx_abort_target,
+ .lun_reset = qla24xx_lun_reset,
+ .fabric_login = qla24xx_login_fabric,
+ .fabric_logout = qla24xx_fabric_logout,
+ .calc_req_entries = NULL,
+ .build_iocbs = NULL,
+ .prep_ms_iocb = qla24xx_prep_ms_iocb,
+ .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
+ .read_nvram = qla25xx_read_nvram_data,
+ .write_nvram = qla25xx_write_nvram_data,
+ .fw_dump = qla81xx_fw_dump,
+ .beacon_on = qla24xx_beacon_on,
+ .beacon_off = qla24xx_beacon_off,
+ .beacon_blink = qla24xx_beacon_blink,
+ .read_optrom = qla25xx_read_optrom_data,
+ .write_optrom = qla24xx_write_optrom_data,
+ .get_flash_version = qla24xx_get_flash_version,
+ .start_scsi = qla24xx_start_scsi,
+ .wrt_req_reg = qla24xx_wrt_req_reg,
+ .wrt_rsp_reg = qla24xx_wrt_rsp_reg,
+ .rd_req_reg = qla24xx_rd_req_reg,
+};
+
static inline void
qla2x00_set_isp_flags(struct qla_hw_data *ha)
{
@@ -1567,6 +1589,13 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
ha->device_type |= DT_IIDMA;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
+ case PCI_DEVICE_ID_QLOGIC_ISP8001:
+ ha->device_type |= DT_ISP8001;
+ ha->device_type |= DT_ZIO_SUPPORTED;
+ ha->device_type |= DT_FWI2;
+ ha->device_type |= DT_IIDMA;
+ ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+ break;
}
}
@@ -1629,7 +1658,7 @@ skip_pio:
/* Determine queue resources */
ha->max_queues = 1;
- if (ql2xmaxqueues <= 1 || !IS_QLA25XX(ha))
+ if (ql2xmaxqueues <= 1 || (!IS_QLA25XX(ha) && !IS_QLA81XX(ha)))
goto mqiobase_exit;
ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3),
pci_resource_len(ha->pdev, 3));
@@ -1706,7 +1735,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8432 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 ||
- pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) {
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001) {
bars = pci_select_bars(pdev, IORESOURCE_MEM);
sht = &qla24xx_driver_template;
mem_only = 1;
@@ -1760,6 +1790,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
rsp_length = RESPONSE_ENTRY_CNT_2100;
ha->max_loop_id = SNS_LAST_LOOP_ID_2100;
ha->gid_list_info_size = 4;
+ ha->flash_conf_off = ~0;
+ ha->flash_data_off = ~0;
+ ha->nvram_conf_off = ~0;
+ ha->nvram_data_off = ~0;
ha->isp_ops = &qla2100_isp_ops;
} else if (IS_QLA2200(ha)) {
ha->mbx_count = MAILBOX_REGISTER_COUNT;
@@ -1767,6 +1801,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
rsp_length = RESPONSE_ENTRY_CNT_2100;
ha->max_loop_id = SNS_LAST_LOOP_ID_2100;
ha->gid_list_info_size = 4;
+ ha->flash_conf_off = ~0;
+ ha->flash_data_off = ~0;
+ ha->nvram_conf_off = ~0;
+ ha->nvram_data_off = ~0;
ha->isp_ops = &qla2100_isp_ops;
} else if (IS_QLA23XX(ha)) {
ha->mbx_count = MAILBOX_REGISTER_COUNT;
@@ -1776,6 +1814,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->gid_list_info_size = 6;
if (IS_QLA2322(ha) || IS_QLA6322(ha))
ha->optrom_size = OPTROM_SIZE_2322;
+ ha->flash_conf_off = ~0;
+ ha->flash_data_off = ~0;
+ ha->nvram_conf_off = ~0;
+ ha->nvram_data_off = ~0;
ha->isp_ops = &qla2300_isp_ops;
} else if (IS_QLA24XX_TYPE(ha)) {
ha->mbx_count = MAILBOX_REGISTER_COUNT;
@@ -1787,6 +1829,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->optrom_size = OPTROM_SIZE_24XX;
ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA24XX;
ha->isp_ops = &qla24xx_isp_ops;
+ ha->flash_conf_off = FARX_ACCESS_FLASH_CONF;
+ ha->flash_data_off = FARX_ACCESS_FLASH_DATA;
+ ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
+ ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
} else if (IS_QLA25XX(ha)) {
ha->mbx_count = MAILBOX_REGISTER_COUNT;
req_length = REQUEST_ENTRY_CNT_24XX;
@@ -1797,6 +1843,23 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->optrom_size = OPTROM_SIZE_25XX;
ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX;
ha->isp_ops = &qla25xx_isp_ops;
+ ha->flash_conf_off = FARX_ACCESS_FLASH_CONF;
+ ha->flash_data_off = FARX_ACCESS_FLASH_DATA;
+ ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
+ ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
+ } else if (IS_QLA81XX(ha)) {
+ ha->mbx_count = MAILBOX_REGISTER_COUNT;
+ req_length = REQUEST_ENTRY_CNT_24XX;
+ rsp_length = RESPONSE_ENTRY_CNT_2300;
+ ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
+ ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
+ ha->gid_list_info_size = 8;
+ ha->optrom_size = OPTROM_SIZE_81XX;
+ ha->isp_ops = &qla81xx_isp_ops;
+ ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX;
+ ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX;
+ ha->nvram_conf_off = ~0;
+ ha->nvram_data_off = ~0;
}
mutex_init(&ha->vport_lock);
@@ -1935,7 +1998,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
probe_failed:
- qla2x00_free_que(ha, req, rsp);
qla2x00_free_device(base_vha);
scsi_host_put(base_vha->host);
@@ -2458,23 +2520,6 @@ qla2x00_post_aen_work(struct scsi_qla_host *vha, enum fc_host_event_code code,
return qla2x00_post_work(vha, e, 1);
}
-int
-qla2x00_post_hwe_work(struct scsi_qla_host *vha, uint16_t code, uint16_t d1,
- uint16_t d2, uint16_t d3)
-{
- struct qla_work_evt *e;
-
- e = qla2x00_alloc_work(vha, QLA_EVT_HWE_LOG, 1);
- if (!e)
- return QLA_FUNCTION_FAILED;
-
- e->u.hwe.code = code;
- e->u.hwe.d1 = d1;
- e->u.hwe.d2 = d2;
- e->u.hwe.d3 = d3;
- return qla2x00_post_work(vha, e, 1);
-}
-
static void
qla2x00_do_work(struct scsi_qla_host *vha)
{
@@ -2492,10 +2537,6 @@ qla2x00_do_work(struct scsi_qla_host *vha)
fc_host_post_event(vha->host, fc_get_event_number(),
e->u.aen.code, e->u.aen.data);
break;
- case QLA_EVT_HWE_LOG:
- qla2xxx_hw_event_log(vha, e->u.hwe.code, e->u.hwe.d1,
- e->u.hwe.d2, e->u.hwe.d3);
- break;
}
if (e->flags & QLA_EVT_FLAG_FREE)
kfree(e);
@@ -2914,13 +2955,14 @@ qla2x00_timer(scsi_qla_host_t *vha)
/* Firmware interface routines. */
-#define FW_BLOBS 6
+#define FW_BLOBS 7
#define FW_ISP21XX 0
#define FW_ISP22XX 1
#define FW_ISP2300 2
#define FW_ISP2322 3
#define FW_ISP24XX 4
#define FW_ISP25XX 5
+#define FW_ISP81XX 6
#define FW_FILE_ISP21XX "ql2100_fw.bin"
#define FW_FILE_ISP22XX "ql2200_fw.bin"
@@ -2928,6 +2970,7 @@ qla2x00_timer(scsi_qla_host_t *vha)
#define FW_FILE_ISP2322 "ql2322_fw.bin"
#define FW_FILE_ISP24XX "ql2400_fw.bin"
#define FW_FILE_ISP25XX "ql2500_fw.bin"
+#define FW_FILE_ISP81XX "ql8100_fw.bin"
static DEFINE_MUTEX(qla_fw_lock);
@@ -2938,6 +2981,7 @@ static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
{ .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
{ .name = FW_FILE_ISP24XX, },
{ .name = FW_FILE_ISP25XX, },
+ { .name = FW_FILE_ISP81XX, },
};
struct fw_blob *
@@ -2959,6 +3003,8 @@ qla2x00_request_firmware(scsi_qla_host_t *vha)
blob = &qla_fw_blobs[FW_ISP24XX];
} else if (IS_QLA25XX(ha)) {
blob = &qla_fw_blobs[FW_ISP25XX];
+ } else if (IS_QLA81XX(ha)) {
+ blob = &qla_fw_blobs[FW_ISP81XX];
}
mutex_lock(&qla_fw_lock);
@@ -3112,6 +3158,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8001) },
{ 0 },
};
MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
@@ -3200,3 +3247,4 @@ MODULE_FIRMWARE(FW_FILE_ISP2300);
MODULE_FIRMWARE(FW_FILE_ISP2322);
MODULE_FIRMWARE(FW_FILE_ISP24XX);
MODULE_FIRMWARE(FW_FILE_ISP25XX);
+MODULE_FIRMWARE(FW_FILE_ISP81XX);
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index c538ee1b1a31..303f8ee11f25 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -425,27 +425,27 @@ qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat)
#define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4)
static inline uint32_t
-flash_conf_to_access_addr(uint32_t faddr)
+flash_conf_addr(struct qla_hw_data *ha, uint32_t faddr)
{
- return FARX_ACCESS_FLASH_CONF | faddr;
+ return ha->flash_conf_off | faddr;
}
static inline uint32_t
-flash_data_to_access_addr(uint32_t faddr)
+flash_data_addr(struct qla_hw_data *ha, uint32_t faddr)
{
- return FARX_ACCESS_FLASH_DATA | faddr;
+ return ha->flash_data_off | faddr;
}
static inline uint32_t
-nvram_conf_to_access_addr(uint32_t naddr)
+nvram_conf_addr(struct qla_hw_data *ha, uint32_t naddr)
{
- return FARX_ACCESS_NVRAM_CONF | naddr;
+ return ha->nvram_conf_off | naddr;
}
static inline uint32_t
-nvram_data_to_access_addr(uint32_t naddr)
+nvram_data_addr(struct qla_hw_data *ha, uint32_t naddr)
{
- return FARX_ACCESS_NVRAM_DATA | naddr;
+ return ha->nvram_data_off | naddr;
}
static uint32_t
@@ -481,10 +481,12 @@ qla24xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
uint32_t dwords)
{
uint32_t i;
+ struct qla_hw_data *ha = vha->hw;
+
/* Dword reads to flash. */
for (i = 0; i < dwords; i++, faddr++)
- dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(vha->hw,
- flash_data_to_access_addr(faddr)));
+ dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
+ flash_data_addr(ha, faddr)));
return dwptr;
}
@@ -518,7 +520,7 @@ qla24xx_get_flash_manufacturer(struct qla_hw_data *ha, uint8_t *man_id,
{
uint32_t ids;
- ids = qla24xx_read_flash_dword(ha, flash_data_to_access_addr(0xd03ab));
+ ids = qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x03ab));
*man_id = LSB(ids);
*flash_id = MSB(ids);
@@ -530,8 +532,7 @@ qla24xx_get_flash_manufacturer(struct qla_hw_data *ha, uint8_t *man_id,
* Example: ATMEL 0x00 01 45 1F
* Extract MFG and Dev ID from last two bytes.
*/
- ids = qla24xx_read_flash_dword(ha,
- flash_data_to_access_addr(0xd009f));
+ ids = qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x009f));
*man_id = LSB(ids);
*flash_id = MSB(ids);
}
@@ -555,9 +556,13 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
/* Begin with sane defaults. */
loc = locations[0];
- *start = IS_QLA24XX_TYPE(ha) ? FA_FLASH_LAYOUT_ADDR_24:
- FA_FLASH_LAYOUT_ADDR;
-
+ *start = 0;
+ if (IS_QLA24XX_TYPE(ha))
+ *start = FA_FLASH_LAYOUT_ADDR_24;
+ else if (IS_QLA25XX(ha))
+ *start = FA_FLASH_LAYOUT_ADDR;
+ else if (IS_QLA81XX(ha))
+ *start = FA_FLASH_LAYOUT_ADDR_81;
/* Begin with first PCI expansion ROM header. */
buf = (uint8_t *)req->ring;
dcode = (uint32_t *)req->ring;
@@ -618,6 +623,22 @@ static void
qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
{
const char *loc, *locations[] = { "DEF", "FLT" };
+ const uint32_t def_fw[] =
+ { FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR_81 };
+ const uint32_t def_boot[] =
+ { FA_BOOT_CODE_ADDR, FA_BOOT_CODE_ADDR, FA_BOOT_CODE_ADDR_81 };
+ const uint32_t def_vpd_nvram[] =
+ { FA_VPD_NVRAM_ADDR, FA_VPD_NVRAM_ADDR, FA_VPD_NVRAM_ADDR_81 };
+ const uint32_t def_fdt[] =
+ { FA_FLASH_DESCR_ADDR_24, FA_FLASH_DESCR_ADDR,
+ FA_FLASH_DESCR_ADDR_81 };
+ const uint32_t def_npiv_conf0[] =
+ { FA_NPIV_CONF0_ADDR_24, FA_NPIV_CONF0_ADDR,
+ FA_NPIV_CONF0_ADDR_81 };
+ const uint32_t def_npiv_conf1[] =
+ { FA_NPIV_CONF1_ADDR_24, FA_NPIV_CONF1_ADDR,
+ FA_NPIV_CONF1_ADDR_81 };
+ uint32_t def;
uint16_t *wptr;
uint16_t cnt, chksum;
uint32_t start;
@@ -676,20 +697,12 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
case FLT_REG_FDT:
ha->flt_region_fdt = start;
break;
- case FLT_REG_HW_EVENT_0:
- if (!PCI_FUNC(ha->pdev->devfn))
- ha->flt_region_hw_event = start;
- break;
- case FLT_REG_HW_EVENT_1:
- if (PCI_FUNC(ha->pdev->devfn))
- ha->flt_region_hw_event = start;
- break;
case FLT_REG_NPIV_CONF_0:
- if (!PCI_FUNC(ha->pdev->devfn))
+ if (!(PCI_FUNC(ha->pdev->devfn) & 1))
ha->flt_region_npiv_conf = start;
break;
case FLT_REG_NPIV_CONF_1:
- if (PCI_FUNC(ha->pdev->devfn))
+ if (PCI_FUNC(ha->pdev->devfn) & 1)
ha->flt_region_npiv_conf = start;
break;
}
@@ -699,22 +712,24 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
no_flash_data:
/* Use hardcoded defaults. */
loc = locations[0];
- ha->flt_region_fw = FA_RISC_CODE_ADDR;
- ha->flt_region_boot = FA_BOOT_CODE_ADDR;
- ha->flt_region_vpd_nvram = FA_VPD_NVRAM_ADDR;
- ha->flt_region_fdt = IS_QLA24XX_TYPE(ha) ? FA_FLASH_DESCR_ADDR_24:
- FA_FLASH_DESCR_ADDR;
- ha->flt_region_hw_event = !PCI_FUNC(ha->pdev->devfn) ?
- FA_HW_EVENT0_ADDR: FA_HW_EVENT1_ADDR;
- ha->flt_region_npiv_conf = !PCI_FUNC(ha->pdev->devfn) ?
- (IS_QLA24XX_TYPE(ha) ? FA_NPIV_CONF0_ADDR_24: FA_NPIV_CONF0_ADDR):
- (IS_QLA24XX_TYPE(ha) ? FA_NPIV_CONF1_ADDR_24: FA_NPIV_CONF1_ADDR);
+ def = 0;
+ if (IS_QLA24XX_TYPE(ha))
+ def = 0;
+ else if (IS_QLA25XX(ha))
+ def = 1;
+ else if (IS_QLA81XX(ha))
+ def = 2;
+ ha->flt_region_fw = def_fw[def];
+ ha->flt_region_boot = def_boot[def];
+ ha->flt_region_vpd_nvram = def_vpd_nvram[def];
+ ha->flt_region_fdt = def_fdt[def];
+ ha->flt_region_npiv_conf = !(PCI_FUNC(ha->pdev->devfn) & 1) ?
+ def_npiv_conf0[def]: def_npiv_conf1[def];
done:
DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x "
- "vpd_nvram=0x%x fdt=0x%x flt=0x%x hwe=0x%x npiv=0x%x.\n", loc,
+ "vpd_nvram=0x%x fdt=0x%x flt=0x%x npiv=0x%x.\n", loc,
ha->flt_region_boot, ha->flt_region_fw, ha->flt_region_vpd_nvram,
- ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_hw_event,
- ha->flt_region_npiv_conf));
+ ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_npiv_conf));
}
static void
@@ -757,14 +772,14 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha)
mid = le16_to_cpu(fdt->man_id);
fid = le16_to_cpu(fdt->id);
ha->fdt_wrt_disable = fdt->wrt_disable_bits;
- ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd);
+ ha->fdt_erase_cmd = flash_conf_addr(ha, 0x0300 | fdt->erase_cmd);
ha->fdt_block_size = le32_to_cpu(fdt->block_size);
if (fdt->unprotect_sec_cmd) {
- ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0300 |
+ ha->fdt_unprotect_sec_cmd = flash_conf_addr(ha, 0x0300 |
fdt->unprotect_sec_cmd);
ha->fdt_protect_sec_cmd = fdt->protect_sec_cmd ?
- flash_conf_to_access_addr(0x0300 | fdt->protect_sec_cmd):
- flash_conf_to_access_addr(0x0336);
+ flash_conf_addr(ha, 0x0300 | fdt->protect_sec_cmd):
+ flash_conf_addr(ha, 0x0336);
}
goto done;
no_flash_data:
@@ -773,7 +788,7 @@ no_flash_data:
mid = man_id;
fid = flash_id;
ha->fdt_wrt_disable = 0x9c;
- ha->fdt_erase_cmd = flash_conf_to_access_addr(0x03d8);
+ ha->fdt_erase_cmd = flash_conf_addr(ha, 0x03d8);
switch (man_id) {
case 0xbf: /* STT flash. */
if (flash_id == 0x8e)
@@ -782,16 +797,16 @@ no_flash_data:
ha->fdt_block_size = FLASH_BLK_SIZE_32K;
if (flash_id == 0x80)
- ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0352);
+ ha->fdt_erase_cmd = flash_conf_addr(ha, 0x0352);
break;
case 0x13: /* ST M25P80. */
ha->fdt_block_size = FLASH_BLK_SIZE_64K;
break;
case 0x1f: /* Atmel 26DF081A. */
ha->fdt_block_size = FLASH_BLK_SIZE_4K;
- ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0320);
- ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0339);
- ha->fdt_protect_sec_cmd = flash_conf_to_access_addr(0x0336);
+ ha->fdt_erase_cmd = flash_conf_addr(ha, 0x0320);
+ ha->fdt_unprotect_sec_cmd = flash_conf_addr(ha, 0x0339);
+ ha->fdt_protect_sec_cmd = flash_conf_addr(ha, 0x0336);
break;
default:
/* Default to 64 kb sector size. */
@@ -813,7 +828,7 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha)
uint32_t flt_addr;
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha))
+ if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA81XX(ha))
return QLA_SUCCESS;
ret = qla2xxx_find_flt_start(vha, &flt_addr);
@@ -838,7 +853,7 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
struct qla_npiv_entry *entry;
struct qla_hw_data *ha = vha->hw;
- if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha))
+ if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA81XX(ha))
return;
ha->isp_ops->read_optrom(vha, (uint8_t *)&hdr,
@@ -930,9 +945,9 @@ qla24xx_unprotect_flash(struct qla_hw_data *ha)
return;
/* Disable flash write-protection. */
- qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);
+ qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0);
/* Some flash parts need an additional zero-write to clear bits.*/
- qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0);
+ qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0);
}
static void
@@ -945,11 +960,10 @@ qla24xx_protect_flash(struct qla_hw_data *ha)
goto skip_wrt_protect;
/* Enable flash write-protection and wait for completion. */
- qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101),
+ qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101),
ha->fdt_wrt_disable);
for (cnt = 300; cnt &&
- qla24xx_read_flash_dword(ha,
- flash_conf_to_access_addr(0x005)) & BIT_0;
+ qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x005)) & BIT_0;
cnt--) {
udelay(10);
}
@@ -977,7 +991,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
ret = QLA_SUCCESS;
/* Prepare burst-capable write on supported ISPs. */
- if (IS_QLA25XX(ha) && !(faddr & 0xfff) &&
+ if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && !(faddr & 0xfff) &&
dwords > OPTROM_BURST_DWORDS) {
optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
&optrom_dma, GFP_KERNEL);
@@ -989,7 +1003,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
}
rest_addr = (ha->fdt_block_size >> 2) - 1;
- sec_mask = 0x80000 - (ha->fdt_block_size >> 2);
+ sec_mask = (ha->optrom_size >> 2) - (ha->fdt_block_size >> 2);
qla24xx_unprotect_flash(ha);
@@ -1024,13 +1038,13 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
*s = cpu_to_le32(*d);
ret = qla2x00_load_ram(vha, optrom_dma,
- flash_data_to_access_addr(faddr),
+ flash_data_addr(ha, faddr),
OPTROM_BURST_DWORDS);
if (ret != QLA_SUCCESS) {
qla_printk(KERN_WARNING, ha,
"Unable to burst-write optrom segment "
"(%x/%x/%llx).\n", ret,
- flash_data_to_access_addr(faddr),
+ flash_data_addr(ha, faddr),
(unsigned long long)optrom_dma);
qla_printk(KERN_WARNING, ha,
"Reverting to slow-write.\n");
@@ -1047,7 +1061,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
}
ret = qla24xx_write_flash_dword(ha,
- flash_data_to_access_addr(faddr), cpu_to_le32(*dwptr));
+ flash_data_addr(ha, faddr), cpu_to_le32(*dwptr));
if (ret != QLA_SUCCESS) {
DEBUG9(printk("%s(%ld) Unable to program flash "
"address=%x data=%x.\n", __func__,
@@ -1098,12 +1112,13 @@ qla24xx_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
{
uint32_t i;
uint32_t *dwptr;
+ struct qla_hw_data *ha = vha->hw;
/* Dword reads to flash. */
dwptr = (uint32_t *)buf;
for (i = 0; i < bytes >> 2; i++, naddr++)
- dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(vha->hw,
- nvram_data_to_access_addr(naddr)));
+ dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
+ nvram_data_addr(ha, naddr)));
return buf;
}
@@ -1160,17 +1175,14 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
RD_REG_DWORD(&reg->ctrl_status); /* PCI Posting. */
/* Disable NVRAM write-protection. */
- qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101),
- 0);
- qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101),
- 0);
+ qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0);
+ qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0);
/* Dword writes to flash. */
dwptr = (uint32_t *)buf;
for (i = 0; i < bytes >> 2; i++, naddr++, dwptr++) {
ret = qla24xx_write_flash_dword(ha,
- nvram_data_to_access_addr(naddr),
- cpu_to_le32(*dwptr));
+ nvram_data_addr(ha, naddr), cpu_to_le32(*dwptr));
if (ret != QLA_SUCCESS) {
DEBUG9(qla_printk("Unable to program nvram address=%x "
"data=%x.\n", naddr, *dwptr));
@@ -1179,8 +1191,7 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
}
/* Enable NVRAM write-protection. */
- qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101),
- 0x8c);
+ qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0x8c);
/* Disable flash write. */
WRT_REG_DWORD(&reg->ctrl_status,
@@ -1202,8 +1213,7 @@ qla25xx_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr,
dwptr = (uint32_t *)buf;
for (i = 0; i < bytes >> 2; i++, naddr++)
dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
- flash_data_to_access_addr(ha->flt_region_vpd_nvram |
- naddr)));
+ flash_data_addr(ha, ha->flt_region_vpd_nvram | naddr)));
return buf;
}
@@ -2246,12 +2256,12 @@ qla25xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf,
burst = left;
rval = qla2x00_dump_ram(vha, optrom_dma,
- flash_data_to_access_addr(faddr), burst);
+ flash_data_addr(ha, faddr), burst);
if (rval) {
qla_printk(KERN_WARNING, ha,
"Unable to burst-read optrom segment "
"(%x/%x/%llx).\n", rval,
- flash_data_to_access_addr(faddr),
+ flash_data_addr(ha, faddr),
(unsigned long long)optrom_dma);
qla_printk(KERN_WARNING, ha,
"Reverting to slow-read.\n");
@@ -2648,108 +2658,3 @@ qla2xxx_get_vpd_field(scsi_qla_host_t *vha, char *key, char *str, size_t size)
return 0;
}
-
-static int
-qla2xxx_hw_event_store(scsi_qla_host_t *vha, uint32_t *fdata)
-{
- uint32_t d[2], faddr;
- struct qla_hw_data *ha = vha->hw;
-
- /* Locate first empty entry. */
- for (;;) {
- if (ha->hw_event_ptr >=
- ha->flt_region_hw_event + FA_HW_EVENT_SIZE) {
- DEBUG2(qla_printk(KERN_WARNING, ha,
- "HW event -- Log Full!\n"));
- return QLA_MEMORY_ALLOC_FAILED;
- }
-
- qla24xx_read_flash_data(vha, d, ha->hw_event_ptr, 2);
- faddr = flash_data_to_access_addr(ha->hw_event_ptr);
- ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE;
- if (d[0] == __constant_cpu_to_le32(0xffffffff) &&
- d[1] == __constant_cpu_to_le32(0xffffffff)) {
- qla24xx_unprotect_flash(ha);
-
- qla24xx_write_flash_dword(ha, faddr++,
- cpu_to_le32(jiffies));
- qla24xx_write_flash_dword(ha, faddr++, 0);
- qla24xx_write_flash_dword(ha, faddr++, *fdata++);
- qla24xx_write_flash_dword(ha, faddr++, *fdata);
-
- qla24xx_protect_flash(ha);
- break;
- }
- }
- return QLA_SUCCESS;
-}
-
-int
-qla2xxx_hw_event_log(scsi_qla_host_t *vha, uint16_t code, uint16_t d1,
- uint16_t d2, uint16_t d3)
-{
-#define QMARK(a, b, c, d) \
- cpu_to_le32(LSB(a) << 24 | LSB(b) << 16 | LSB(c) << 8 | LSB(d))
- struct qla_hw_data *ha = vha->hw;
- int rval;
- uint32_t marker[2], fdata[4];
-
- if (ha->flt_region_hw_event == 0)
- return QLA_FUNCTION_FAILED;
-
- DEBUG2(qla_printk(KERN_WARNING, ha,
- "HW event -- code=%x, d1=%x, d2=%x, d3=%x.\n", code, d1, d2, d3));
-
- /* If marker not already found, locate or write. */
- if (!ha->flags.hw_event_marker_found) {
- /* Create marker. */
- marker[0] = QMARK('L', ha->fw_major_version,
- ha->fw_minor_version, ha->fw_subminor_version);
- marker[1] = QMARK(QLA_DRIVER_MAJOR_VER, QLA_DRIVER_MINOR_VER,
- QLA_DRIVER_PATCH_VER, QLA_DRIVER_BETA_VER);
-
- /* Locate marker. */
- ha->hw_event_ptr = ha->flt_region_hw_event;
- for (;;) {
- qla24xx_read_flash_data(vha, fdata, ha->hw_event_ptr,
- 4);
- if (fdata[0] == __constant_cpu_to_le32(0xffffffff) &&
- fdata[1] == __constant_cpu_to_le32(0xffffffff))
- break;
- ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE;
- if (ha->hw_event_ptr >=
- ha->flt_region_hw_event + FA_HW_EVENT_SIZE) {
- DEBUG2(qla_printk(KERN_WARNING, ha,
- "HW event -- Log Full!\n"));
- return QLA_MEMORY_ALLOC_FAILED;
- }
- if (fdata[2] == marker[0] && fdata[3] == marker[1]) {
- ha->flags.hw_event_marker_found = 1;
- break;
- }
- }
- /* No marker, write it. */
- if (!ha->flags.hw_event_marker_found) {
- rval = qla2xxx_hw_event_store(vha, marker);
- if (rval != QLA_SUCCESS) {
- DEBUG2(qla_printk(KERN_WARNING, ha,
- "HW event -- Failed marker write=%x.!\n",
- rval));
- return rval;
- }
- ha->flags.hw_event_marker_found = 1;
- }
- }
-
- /* Store error. */
- fdata[0] = cpu_to_le32(code << 16 | d1);
- fdata[1] = cpu_to_le32(d2 << 16 | d3);
- rval = qla2xxx_hw_event_store(vha, fdata);
- if (rval != QLA_SUCCESS) {
- DEBUG2(qla_printk(KERN_WARNING, ha,
- "HW event -- Failed error write=%x.!\n",
- rval));
- }
-
- return rval;
-}
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index be22f3a09f8d..808bab6ef06b 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.02.03-k1"
+#define QLA2XXX_VERSION "8.03.00-k1"
#define QLA_DRIVER_MAJOR_VER 8
-#define QLA_DRIVER_MINOR_VER 2
-#define QLA_DRIVER_PATCH_VER 3
+#define QLA_DRIVER_MINOR_VER 3
+#define QLA_DRIVER_PATCH_VER 0
#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index c577d79bd7e8..051b0f5e8c8e 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -392,7 +392,7 @@ int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
ha->iocb_hiwat -= IOCB_HIWAT_CUSHION;
else
dev_info(&ha->pdev->dev, "WARNING!!! You have less than %d "
- "firmare IOCBs available (%d).\n",
+ "firmware IOCBs available (%d).\n",
IOCB_HIWAT_CUSHION, ha->iocb_hiwat);
return QLA_SUCCESS;
diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c
index 913a931176ef..8e5c169b03fb 100644
--- a/drivers/scsi/raid_class.c
+++ b/drivers/scsi/raid_class.c
@@ -237,8 +237,7 @@ int raid_component_add(struct raid_template *r,struct device *raid_dev,
rc->dev.parent = get_device(component_dev);
rc->num = rd->component_count++;
- snprintf(rc->dev.bus_id, sizeof(rc->dev.bus_id),
- "component-%d", rc->num);
+ dev_set_name(&rc->dev, "component-%d", rc->num);
list_add_tail(&rc->node, &rd->component_list);
rc->dev.class = &raid_class.class;
err = device_add(&rc->dev);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index f8b79d401d58..cbcd3f681b62 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -651,10 +651,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
unsigned long timeout;
int rtn = 0;
- /*
- * We will use a queued command if possible, otherwise we will
- * emulate the queuing and calling of completion function ourselves.
- */
atomic_inc(&cmd->device->iorequest_cnt);
/* check if the device is still usable */
@@ -1099,7 +1095,8 @@ EXPORT_SYMBOL(__starget_for_each_device);
* 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.
+ * any access to the returned scsi_device. A scsi_device in state
+ * SDEV_DEL is skipped.
*
* Note: The only reason why drivers should use this is because
* they need to access the device list in irq context. Otherwise you
@@ -1111,6 +1108,8 @@ struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget,
struct scsi_device *sdev;
list_for_each_entry(sdev, &starget->devices, same_target_siblings) {
+ if (sdev->sdev_state == SDEV_DEL)
+ continue;
if (sdev->lun ==lun)
return sdev;
}
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 27c633f55794..6eebd0bbe8a8 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -2508,7 +2508,7 @@ static void pseudo_0_release(struct device *dev)
}
static struct device pseudo_primary = {
- .bus_id = "pseudo_0",
+ .init_name = "pseudo_0",
.release = pseudo_0_release,
};
@@ -2680,7 +2680,7 @@ static int sdebug_add_adapter(void)
sdbg_host->dev.bus = &pseudo_lld_bus;
sdbg_host->dev.parent = &pseudo_primary;
sdbg_host->dev.release = &sdebug_release_adapter;
- sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
+ dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host);
error = device_register(&sdbg_host->dev);
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 4969e4ec75ea..099b5455bbce 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -224,6 +224,7 @@ static struct {
{"SGI", "TP9100", "*", BLIST_REPORTLUN2},
{"SGI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
{"IBM", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
+ {"SUN", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
{"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36},
{"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN},
{"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 381838ebd460..ad6a1370761e 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -124,34 +124,22 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
enum blk_eh_timer_return scsi_times_out(struct request *req)
{
struct scsi_cmnd *scmd = req->special;
- enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);
enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED;
scsi_log_completion(scmd, TIMEOUT_ERROR);
if (scmd->device->host->transportt->eh_timed_out)
- eh_timed_out = scmd->device->host->transportt->eh_timed_out;
+ rtn = scmd->device->host->transportt->eh_timed_out(scmd);
else if (scmd->device->host->hostt->eh_timed_out)
- eh_timed_out = scmd->device->host->hostt->eh_timed_out;
- else
- eh_timed_out = NULL;
+ rtn = scmd->device->host->hostt->eh_timed_out(scmd);
- if (eh_timed_out) {
- rtn = eh_timed_out(scmd);
- switch (rtn) {
- case BLK_EH_NOT_HANDLED:
- break;
- default:
- return rtn;
- }
- }
-
- if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
+ if (unlikely(rtn == BLK_EH_NOT_HANDLED &&
+ !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
scmd->result |= DID_TIME_OUT << 16;
- return BLK_EH_HANDLED;
+ rtn = BLK_EH_HANDLED;
}
- return BLK_EH_NOT_HANDLED;
+ return rtn;
}
/**
@@ -1650,7 +1638,7 @@ int scsi_error_handler(void *data)
* We use TASK_INTERRUPTIBLE so that the thread is not
* counted against the load average as a running process.
* We never actually get interrupted because kthread_run
- * disables singal delivery for the created thread.
+ * disables signal delivery for the created thread.
*/
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 2ae4f8fc5831..b98f763931c5 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -167,10 +167,17 @@ EXPORT_SYMBOL(scsi_set_medium_removal);
static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg)
{
struct device *dev = scsi_get_device(sdev->host);
+ const char *name;
if (!dev)
return -ENXIO;
- return copy_to_user(arg, dev->bus_id, sizeof(dev->bus_id))? -EFAULT: 0;
+
+ name = dev_name(dev);
+
+ /* compatibility with old ioctl which only returned
+ * 20 characters */
+ return copy_to_user(arg, name, min(strlen(name), (size_t)20))
+ ? -EFAULT: 0;
}
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index f2f51e0333eb..940dc32ff0dc 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -91,26 +91,19 @@ static void scsi_unprep_request(struct request *req)
scsi_put_command(cmd);
}
-/*
- * Function: scsi_queue_insert()
- *
- * Purpose: Insert a command in the midlevel queue.
- *
- * Arguments: cmd - command that we are adding to queue.
- * reason - why we are inserting command to queue.
- *
- * Lock status: Assumed that lock is not held upon entry.
- *
- * Returns: Nothing.
- *
- * Notes: We do this for one of two cases. Either the host is busy
- * and it cannot accept any more commands for the time being,
- * or the device returned QUEUE_FULL and can accept no more
- * commands.
- * Notes: This could be called either from an interrupt context or a
- * normal process context.
+/**
+ * __scsi_queue_insert - private queue insertion
+ * @cmd: The SCSI command being requeued
+ * @reason: The reason for the requeue
+ * @unbusy: Whether the queue should be unbusied
+ *
+ * This is a private queue insertion. The public interface
+ * scsi_queue_insert() always assumes the queue should be unbusied
+ * because it's always called before the completion. This function is
+ * for a requeue after completion, which should only occur in this
+ * file.
*/
-int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
+static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy)
{
struct Scsi_Host *host = cmd->device->host;
struct scsi_device *device = cmd->device;
@@ -150,7 +143,8 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
* Decrement the counters, since these commands are no longer
* active on the host/device.
*/
- scsi_device_unbusy(device);
+ if (unbusy)
+ scsi_device_unbusy(device);
/*
* Requeue this command. It will go before all other commands
@@ -172,6 +166,29 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
return 0;
}
+/*
+ * Function: scsi_queue_insert()
+ *
+ * Purpose: Insert a command in the midlevel queue.
+ *
+ * Arguments: cmd - command that we are adding to queue.
+ * reason - why we are inserting command to queue.
+ *
+ * Lock status: Assumed that lock is not held upon entry.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: We do this for one of two cases. Either the host is busy
+ * and it cannot accept any more commands for the time being,
+ * or the device returned QUEUE_FULL and can accept no more
+ * commands.
+ * Notes: This could be called either from an interrupt context or a
+ * normal process context.
+ */
+int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
+{
+ return __scsi_queue_insert(cmd, reason, 1);
+}
/**
* scsi_execute - insert request and wait for the result
* @sdev: scsi device
@@ -684,6 +701,8 @@ void scsi_run_host_queues(struct Scsi_Host *shost)
scsi_run_queue(sdev->request_queue);
}
+static void __scsi_release_buffers(struct scsi_cmnd *, int);
+
/*
* Function: scsi_end_request()
*
@@ -732,6 +751,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error,
* leftovers in the front of the
* queue, and goose the queue again.
*/
+ scsi_release_buffers(cmd);
scsi_requeue_command(q, cmd);
cmd = NULL;
}
@@ -743,6 +763,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error,
* This will goose the queue request function at the end, so we don't
* need to worry about launching another command.
*/
+ __scsi_release_buffers(cmd, 0);
scsi_next_command(cmd);
return NULL;
}
@@ -798,6 +819,26 @@ static void scsi_free_sgtable(struct scsi_data_buffer *sdb)
__sg_free_table(&sdb->table, SCSI_MAX_SG_SEGMENTS, scsi_sg_free);
}
+static void __scsi_release_buffers(struct scsi_cmnd *cmd, int do_bidi_check)
+{
+
+ if (cmd->sdb.table.nents)
+ scsi_free_sgtable(&cmd->sdb);
+
+ memset(&cmd->sdb, 0, sizeof(cmd->sdb));
+
+ if (do_bidi_check && scsi_bidi_cmnd(cmd)) {
+ struct scsi_data_buffer *bidi_sdb =
+ cmd->request->next_rq->special;
+ scsi_free_sgtable(bidi_sdb);
+ kmem_cache_free(scsi_sdb_cache, bidi_sdb);
+ cmd->request->next_rq->special = NULL;
+ }
+
+ if (scsi_prot_sg_count(cmd))
+ scsi_free_sgtable(cmd->prot_sdb);
+}
+
/*
* Function: scsi_release_buffers()
*
@@ -817,21 +858,7 @@ static void scsi_free_sgtable(struct scsi_data_buffer *sdb)
*/
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_sdb_cache, bidi_sdb);
- cmd->request->next_rq->special = NULL;
- }
-
- if (scsi_prot_sg_count(cmd))
- scsi_free_sgtable(cmd->prot_sdb);
+ __scsi_release_buffers(cmd, 1);
}
EXPORT_SYMBOL(scsi_release_buffers);
@@ -945,7 +972,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
}
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
@@ -963,6 +989,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
return;
this_count = blk_rq_bytes(req);
+ error = -EIO;
+
if (host_byte(result) == DID_RESET) {
/* Third party bus reset or reset for error recovery
* reasons. Just retry the command and see what
@@ -1004,13 +1032,18 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
/* This will issue a new 6-byte command. */
cmd->device->use_10_for_rw = 0;
action = ACTION_REPREP;
+ } else if (sshdr.asc == 0x10) /* DIX */ {
+ description = "Host Data Integrity Failure";
+ action = ACTION_FAIL;
+ error = -EILSEQ;
} else
action = ACTION_FAIL;
break;
case ABORTED_COMMAND:
if (sshdr.asc == 0x10) { /* DIF */
+ description = "Target Data Integrity Failure";
action = ACTION_FAIL;
- description = "Data Integrity Failure";
+ error = -EILSEQ;
} else
action = ACTION_RETRY;
break;
@@ -1029,6 +1062,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
case 0x09: /* self test in progress */
action = ACTION_DELAYED_RETRY;
break;
+ default:
+ description = "Device not ready";
+ action = ACTION_FAIL;
+ break;
}
} else {
description = "Device not ready";
@@ -1052,9 +1089,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
switch (action) {
case ACTION_FAIL:
/* Give up and fail the remainder of the request */
+ scsi_release_buffers(cmd);
if (!(req->cmd_flags & REQ_QUIET)) {
if (description)
- scmd_printk(KERN_INFO, cmd, "%s",
+ scmd_printk(KERN_INFO, cmd, "%s\n",
description);
scsi_print_result(cmd);
if (driver_byte(result) & DRIVER_SENSE)
@@ -1067,15 +1105,16 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
/* Unprep the request and put it back at the head of the queue.
* A new command will be prepared and issued.
*/
+ scsi_release_buffers(cmd);
scsi_requeue_command(q, cmd);
break;
case ACTION_RETRY:
/* Retry the same command immediately */
- scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY);
+ __scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY, 0);
break;
case ACTION_DELAYED_RETRY:
/* Retry the same command after a delay */
- scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+ __scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY, 0);
break;
}
}
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 18486b51668d..66505bb79410 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/spinlock.h>
+#include <linux/async.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -179,6 +180,8 @@ int scsi_complete_async_scans(void)
spin_unlock(&async_scan_lock);
kfree(data);
+ /* Synchronize async operations globally */
+ async_synchronize_full();
return 0;
}
@@ -411,8 +414,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
device_initialize(dev);
starget->reap_ref = 1;
dev->parent = get_device(parent);
- sprintf(dev->bus_id, "target%d:%d:%d",
- shost->host_no, channel, id);
+ dev_set_name(dev, "target%d:%d:%d", shost->host_no, channel, id);
#ifndef CONFIG_SYSFS_DEPRECATED
dev->bus = &scsi_bus_type;
#endif
@@ -1021,7 +1023,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
if (rescan || !scsi_device_created(sdev)) {
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
"scsi scan: device exists on %s\n",
- sdev->sdev_gendev.bus_id));
+ dev_name(&sdev->sdev_gendev)));
if (sdevp)
*sdevp = sdev;
else
@@ -1160,7 +1162,7 @@ static void scsi_sequential_lun_scan(struct scsi_target *starget,
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: Sequential scan of"
- "%s\n", starget->dev.bus_id));
+ "%s\n", dev_name(&starget->dev)));
max_dev_lun = min(max_scsi_luns, shost->max_lun);
/*
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 93c28f30bbd7..da63802cbf9d 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -1079,16 +1079,14 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
device_initialize(&sdev->sdev_gendev);
sdev->sdev_gendev.bus = &scsi_bus_type;
sdev->sdev_gendev.type = &scsi_dev_type;
- sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d",
- sdev->host->host_no, sdev->channel, sdev->id,
- sdev->lun);
-
+ dev_set_name(&sdev->sdev_gendev, "%d:%d:%d:%d",
+ sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
+
device_initialize(&sdev->sdev_dev);
sdev->sdev_dev.parent = &sdev->sdev_gendev;
sdev->sdev_dev.class = &sdev_class;
- snprintf(sdev->sdev_dev.bus_id, BUS_ID_SIZE,
- "%d:%d:%d:%d", sdev->host->host_no,
- sdev->channel, sdev->id, sdev->lun);
+ dev_set_name(&sdev->sdev_dev, "%d:%d:%d:%d",
+ sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
sdev->scsi_level = starget->scsi_level;
transport_setup_device(&sdev->sdev_gendev);
spin_lock_irqsave(shost->host_lock, flags);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 062304de4854..5f77417ed585 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -2407,8 +2407,12 @@ fc_rport_final_delete(struct work_struct *work)
/*
* Notify the driver that the rport is now dead. The LLDD will
* also guarantee that any communication to the rport is terminated
+ *
+ * Avoid this call if we already called it when we preserved the
+ * rport for the binding.
*/
- if (i->f->dev_loss_tmo_callbk)
+ if (!(rport->flags & FC_RPORT_DEVLOSS_CALLBK_DONE) &&
+ (i->f->dev_loss_tmo_callbk))
i->f->dev_loss_tmo_callbk(rport);
transport_remove_device(dev);
@@ -2486,8 +2490,8 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
device_initialize(dev); /* takes self reference */
dev->parent = get_device(&shost->shost_gendev); /* parent reference */
dev->release = fc_rport_dev_release;
- sprintf(dev->bus_id, "rport-%d:%d-%d",
- shost->host_no, channel, rport->number);
+ dev_set_name(dev, "rport-%d:%d-%d",
+ shost->host_no, channel, rport->number);
transport_setup_device(dev);
error = device_add(dev);
@@ -2647,7 +2651,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
spin_lock_irqsave(shost->host_lock, flags);
rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT |
- FC_RPORT_DEVLOSS_PENDING);
+ FC_RPORT_DEVLOSS_PENDING |
+ FC_RPORT_DEVLOSS_CALLBK_DONE);
/* if target, initiate a scan */
if (rport->scsi_target_id != -1) {
@@ -2944,6 +2949,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
struct fc_rport *rport =
container_of(work, struct fc_rport, dev_loss_work.work);
struct Scsi_Host *shost = rport_to_shost(rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
unsigned long flags;
@@ -3011,6 +3017,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
rport->roles = FC_PORT_ROLE_UNKNOWN;
rport->port_state = FC_PORTSTATE_NOTPRESENT;
rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT;
+ rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE;
/*
* Pre-emptively kill I/O rather than waiting for the work queue
@@ -3046,8 +3053,18 @@ fc_timeout_deleted_rport(struct work_struct *work)
* all attached scsi devices.
*/
fc_queue_work(shost, &rport->stgt_delete_work);
+
+ /*
+ * Notify the driver that the rport is now dead. The LLDD will
+ * also guarantee that any communication to the rport is terminated
+ *
+ * Note: we set the CALLBK_DONE flag above to correspond
+ */
+ if (i->f->dev_loss_tmo_callbk)
+ i->f->dev_loss_tmo_callbk(rport);
}
+
/**
* fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a disconnected SCSI target.
* @work: rport to terminate io on.
@@ -3164,8 +3181,8 @@ fc_vport_setup(struct Scsi_Host *shost, int channel, struct device *pdev,
device_initialize(dev); /* takes self reference */
dev->parent = get_device(pdev); /* takes parent reference */
dev->release = fc_vport_dev_release;
- sprintf(dev->bus_id, "vport-%d:%d-%d",
- shost->host_no, channel, vport->number);
+ dev_set_name(dev, "vport-%d:%d-%d",
+ shost->host_no, channel, vport->number);
transport_setup_device(dev);
error = device_add(dev);
@@ -3188,19 +3205,19 @@ fc_vport_setup(struct Scsi_Host *shost, int channel, struct device *pdev,
*/
if (pdev != &shost->shost_gendev) {
error = sysfs_create_link(&shost->shost_gendev.kobj,
- &dev->kobj, dev->bus_id);
+ &dev->kobj, dev_name(dev));
if (error)
printk(KERN_ERR
"%s: Cannot create vport symlinks for "
"%s, err=%d\n",
- __func__, dev->bus_id, error);
+ __func__, dev_name(dev), error);
}
spin_lock_irqsave(shost->host_lock, flags);
vport->flags &= ~FC_VPORT_CREATING;
spin_unlock_irqrestore(shost->host_lock, flags);
dev_printk(KERN_NOTICE, pdev,
- "%s created via shost%d channel %d\n", dev->bus_id,
+ "%s created via shost%d channel %d\n", dev_name(dev),
shost->host_no, channel);
*ret_vport = vport;
@@ -3297,7 +3314,7 @@ fc_vport_terminate(struct fc_vport *vport)
return stat;
if (dev->parent != &shost->shost_gendev)
- sysfs_remove_link(&shost->shost_gendev.kobj, dev->bus_id);
+ sysfs_remove_link(&shost->shost_gendev.kobj, dev_name(dev));
transport_remove_device(dev);
device_del(dev);
transport_destroy_device(dev);
@@ -3329,7 +3346,7 @@ fc_vport_sched_delete(struct work_struct *work)
dev_printk(KERN_ERR, vport->dev.parent,
"%s: %s could not be deleted created via "
"shost%d channel %d - error %d\n", __func__,
- vport->dev.bus_id, vport->shost->host_no,
+ dev_name(&vport->dev), vport->shost->host_no,
vport->channel, stat);
}
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 4a803ebaf508..75c9297694cb 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -187,8 +187,7 @@ iscsi_create_endpoint(int dd_size)
ep->id = id;
ep->dev.class = &iscsi_endpoint_class;
- snprintf(ep->dev.bus_id, BUS_ID_SIZE, "ep-%llu",
- (unsigned long long) id);
+ dev_set_name(&ep->dev, "ep-%llu", (unsigned long long) id);
err = device_register(&ep->dev);
if (err)
goto free_ep;
@@ -724,8 +723,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
}
session->target_id = id;
- snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
- session->sid);
+ dev_set_name(&session->dev, "session%u", session->sid);
err = device_add(&session->dev);
if (err) {
iscsi_cls_session_printk(KERN_ERR, session,
@@ -898,8 +896,7 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
if (!get_device(&session->dev))
goto free_conn;
- snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
- session->sid, cid);
+ dev_set_name(&conn->dev, "connection%d:%u", session->sid, cid);
conn->dev.parent = &session->dev;
conn->dev.release = iscsi_conn_release;
err = device_register(&conn->dev);
@@ -1816,7 +1813,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
priv->t.create_work_queue = 1;
priv->dev.class = &iscsi_transport_class;
- snprintf(priv->dev.bus_id, BUS_ID_SIZE, "%s", tt->name);
+ dev_set_name(&priv->dev, "%s", tt->name);
err = device_register(&priv->dev);
if (err)
goto free_priv;
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 366609386be1..50988cbf7b2d 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -207,7 +207,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
struct request_queue *q;
int error;
struct device *dev;
- char namebuf[BUS_ID_SIZE];
+ char namebuf[20];
const char *name;
void (*release)(struct device *);
@@ -219,7 +219,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
if (rphy) {
q = blk_init_queue(sas_non_host_smp_request, NULL);
dev = &rphy->dev;
- name = dev->bus_id;
+ name = dev_name(dev);
release = NULL;
} else {
q = blk_init_queue(sas_host_smp_request, NULL);
@@ -629,10 +629,10 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
INIT_LIST_HEAD(&phy->port_siblings);
if (scsi_is_sas_expander_device(parent)) {
struct sas_rphy *rphy = dev_to_rphy(parent);
- sprintf(phy->dev.bus_id, "phy-%d:%d:%d", shost->host_no,
+ dev_set_name(&phy->dev, "phy-%d:%d:%d", shost->host_no,
rphy->scsi_target_id, number);
} else
- sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number);
+ dev_set_name(&phy->dev, "phy-%d:%d", shost->host_no, number);
transport_setup_device(&phy->dev);
@@ -770,7 +770,7 @@ static void sas_port_create_link(struct sas_port *port,
int res;
res = sysfs_create_link(&port->dev.kobj, &phy->dev.kobj,
- phy->dev.bus_id);
+ dev_name(&phy->dev));
if (res)
goto err;
res = sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port");
@@ -785,7 +785,7 @@ err:
static void sas_port_delete_link(struct sas_port *port,
struct sas_phy *phy)
{
- sysfs_remove_link(&port->dev.kobj, phy->dev.bus_id);
+ sysfs_remove_link(&port->dev.kobj, dev_name(&phy->dev));
sysfs_remove_link(&phy->dev.kobj, "port");
}
@@ -821,11 +821,11 @@ struct sas_port *sas_port_alloc(struct device *parent, int port_id)
if (scsi_is_sas_expander_device(parent)) {
struct sas_rphy *rphy = dev_to_rphy(parent);
- sprintf(port->dev.bus_id, "port-%d:%d:%d", shost->host_no,
- rphy->scsi_target_id, port->port_identifier);
+ dev_set_name(&port->dev, "port-%d:%d:%d", shost->host_no,
+ rphy->scsi_target_id, port->port_identifier);
} else
- sprintf(port->dev.bus_id, "port-%d:%d", shost->host_no,
- port->port_identifier);
+ dev_set_name(&port->dev, "port-%d:%d", shost->host_no,
+ port->port_identifier);
transport_setup_device(&port->dev);
@@ -935,7 +935,7 @@ void sas_port_delete(struct sas_port *port)
if (port->is_backlink) {
struct device *parent = port->dev.parent;
- sysfs_remove_link(&port->dev.kobj, parent->bus_id);
+ sysfs_remove_link(&port->dev.kobj, dev_name(parent));
port->is_backlink = 0;
}
@@ -984,7 +984,8 @@ void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy)
/* If this trips, you added a phy that was already
* part of a different port */
if (unlikely(tmp != phy)) {
- dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n", phy->dev.bus_id);
+ dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n",
+ dev_name(&phy->dev));
BUG();
}
} else {
@@ -1023,7 +1024,7 @@ void sas_port_mark_backlink(struct sas_port *port)
return;
port->is_backlink = 1;
res = sysfs_create_link(&port->dev.kobj, &parent->kobj,
- parent->bus_id);
+ dev_name(parent));
if (res)
goto err;
return;
@@ -1367,11 +1368,12 @@ struct sas_rphy *sas_end_device_alloc(struct sas_port *parent)
rdev->rphy.dev.release = sas_end_device_release;
if (scsi_is_sas_expander_device(parent->dev.parent)) {
struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent);
- sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d:%d",
- shost->host_no, rphy->scsi_target_id, parent->port_identifier);
+ dev_set_name(&rdev->rphy.dev, "end_device-%d:%d:%d",
+ shost->host_no, rphy->scsi_target_id,
+ parent->port_identifier);
} else
- sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d",
- shost->host_no, parent->port_identifier);
+ dev_set_name(&rdev->rphy.dev, "end_device-%d:%d",
+ shost->host_no, parent->port_identifier);
rdev->rphy.identify.device_type = SAS_END_DEVICE;
sas_rphy_initialize(&rdev->rphy);
transport_setup_device(&rdev->rphy.dev);
@@ -1411,8 +1413,8 @@ struct sas_rphy *sas_expander_alloc(struct sas_port *parent,
mutex_lock(&sas_host->lock);
rdev->rphy.scsi_target_id = sas_host->next_expander_id++;
mutex_unlock(&sas_host->lock);
- sprintf(rdev->rphy.dev.bus_id, "expander-%d:%d",
- shost->host_no, rdev->rphy.scsi_target_id);
+ dev_set_name(&rdev->rphy.dev, "expander-%d:%d",
+ shost->host_no, rdev->rphy.scsi_target_id);
rdev->rphy.identify.device_type = type;
sas_rphy_initialize(&rdev->rphy);
transport_setup_device(&rdev->rphy.dev);
@@ -1445,7 +1447,7 @@ int sas_rphy_add(struct sas_rphy *rphy)
transport_add_device(&rphy->dev);
transport_configure_device(&rphy->dev);
if (sas_bsg_initialize(shost, rphy))
- printk("fail to a bsg device %s\n", rphy->dev.bus_id);
+ printk("fail to a bsg device %s\n", dev_name(&rphy->dev));
mutex_lock(&sas_host->lock);
diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c
index 8a7af951d98a..21a045e0559f 100644
--- a/drivers/scsi/scsi_transport_srp.c
+++ b/drivers/scsi/scsi_transport_srp.c
@@ -212,7 +212,7 @@ struct srp_rport *srp_rport_add(struct Scsi_Host *shost,
rport->roles = ids->roles;
id = atomic_inc_return(&to_srp_host_attrs(shost)->next_port_id);
- sprintf(rport->dev.bus_id, "port-%d:%d", shost->host_no, id);
+ dev_set_name(&rport->dev, "port-%d:%d", shost->host_no, id);
transport_setup_device(&rport->dev);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 62b28d58e65e..d57566b8be0a 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -48,6 +48,7 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/string_helpers.h>
+#include <linux/async.h>
#include <asm/uaccess.h>
#include <scsi/scsi.h>
@@ -1802,6 +1803,71 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen)
return 0;
}
+/*
+ * The asynchronous part of sd_probe
+ */
+static void sd_probe_async(void *data, async_cookie_t cookie)
+{
+ struct scsi_disk *sdkp = data;
+ struct scsi_device *sdp;
+ struct gendisk *gd;
+ u32 index;
+ struct device *dev;
+
+ sdp = sdkp->device;
+ gd = sdkp->disk;
+ index = sdkp->index;
+ dev = &sdp->sdev_gendev;
+
+ if (!sdp->request_queue->rq_timeout) {
+ if (sdp->type != TYPE_MOD)
+ blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
+ else
+ blk_queue_rq_timeout(sdp->request_queue,
+ SD_MOD_TIMEOUT);
+ }
+
+ device_initialize(&sdkp->dev);
+ sdkp->dev.parent = &sdp->sdev_gendev;
+ sdkp->dev.class = &sd_disk_class;
+ dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev));
+
+ if (device_add(&sdkp->dev))
+ goto out_free_index;
+
+ get_device(&sdp->sdev_gendev);
+
+ if (index < SD_MAX_DISKS) {
+ gd->major = sd_major((index & 0xf0) >> 4);
+ gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
+ gd->minors = SD_MINORS;
+ }
+ gd->fops = &sd_fops;
+ gd->private_data = &sdkp->driver;
+ gd->queue = sdkp->device->request_queue;
+
+ sd_revalidate_disk(gd);
+
+ blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
+
+ gd->driverfs_dev = &sdp->sdev_gendev;
+ gd->flags = GENHD_FL_EXT_DEVT | GENHD_FL_DRIVERFS;
+ if (sdp->removable)
+ gd->flags |= GENHD_FL_REMOVABLE;
+
+ dev_set_drvdata(dev, sdkp);
+ add_disk(gd);
+ sd_dif_config_host(sdkp);
+
+ sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
+ sdp->removable ? "removable " : "");
+
+ return;
+
+ out_free_index:
+ ida_remove(&sd_index_ida, index);
+}
+
/**
* sd_probe - called during driver initialization and whenever a
* new scsi device is attached to the system. It is called once
@@ -1865,48 +1931,7 @@ static int sd_probe(struct device *dev)
sdkp->openers = 0;
sdkp->previous_state = 1;
- if (!sdp->request_queue->rq_timeout) {
- if (sdp->type != TYPE_MOD)
- blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT);
- else
- blk_queue_rq_timeout(sdp->request_queue,
- SD_MOD_TIMEOUT);
- }
-
- device_initialize(&sdkp->dev);
- sdkp->dev.parent = &sdp->sdev_gendev;
- sdkp->dev.class = &sd_disk_class;
- strncpy(sdkp->dev.bus_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE);
-
- if (device_add(&sdkp->dev))
- goto out_free_index;
-
- get_device(&sdp->sdev_gendev);
-
- if (index < SD_MAX_DISKS) {
- gd->major = sd_major((index & 0xf0) >> 4);
- gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
- gd->minors = SD_MINORS;
- }
- gd->fops = &sd_fops;
- gd->private_data = &sdkp->driver;
- gd->queue = sdkp->device->request_queue;
-
- sd_revalidate_disk(gd);
-
- blk_queue_prep_rq(sdp->request_queue, sd_prep_fn);
-
- gd->driverfs_dev = &sdp->sdev_gendev;
- gd->flags = GENHD_FL_EXT_DEVT | GENHD_FL_DRIVERFS;
- if (sdp->removable)
- gd->flags |= GENHD_FL_REMOVABLE;
-
- dev_set_drvdata(dev, sdkp);
- add_disk(gd);
- sd_dif_config_host(sdkp);
-
- sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
- sdp->removable ? "removable " : "");
+ async_schedule(sd_probe_async, sdkp);
return 0;
diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c
index 3ebb1f289490..184dff492797 100644
--- a/drivers/scsi/sd_dif.c
+++ b/drivers/scsi/sd_dif.c
@@ -142,7 +142,7 @@ static int sd_dif_type1_verify_ip(struct blk_integrity_exchg *bix)
static void sd_dif_type1_set_tag(void *prot, void *tag_buf, unsigned int sectors)
{
struct sd_dif_tuple *sdt = prot;
- char *tag = tag_buf;
+ u8 *tag = tag_buf;
unsigned int i, j;
for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) {
@@ -154,7 +154,7 @@ static void sd_dif_type1_set_tag(void *prot, void *tag_buf, unsigned int sectors
static void sd_dif_type1_get_tag(void *prot, void *tag_buf, unsigned int sectors)
{
struct sd_dif_tuple *sdt = prot;
- char *tag = tag_buf;
+ u8 *tag = tag_buf;
unsigned int i, j;
for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) {
@@ -256,7 +256,7 @@ static int sd_dif_type3_verify_ip(struct blk_integrity_exchg *bix)
static void sd_dif_type3_set_tag(void *prot, void *tag_buf, unsigned int sectors)
{
struct sd_dif_tuple *sdt = prot;
- char *tag = tag_buf;
+ u8 *tag = tag_buf;
unsigned int i, j;
for (i = 0, j = 0 ; i < sectors ; i++, j += 6, sdt++) {
@@ -269,7 +269,7 @@ static void sd_dif_type3_set_tag(void *prot, void *tag_buf, unsigned int sectors
static void sd_dif_type3_get_tag(void *prot, void *tag_buf, unsigned int sectors)
{
struct sd_dif_tuple *sdt = prot;
- char *tag = tag_buf;
+ u8 *tag = tag_buf;
unsigned int i, j;
for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) {
@@ -374,7 +374,10 @@ void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix, unsig
else
csum_convert = 0;
+ BUG_ON(dif && (scmd->cmnd[0] == READ_6 || scmd->cmnd[0] == WRITE_6));
+
switch (scmd->cmnd[0]) {
+ case READ_6:
case READ_10:
case READ_12:
case READ_16:
@@ -390,6 +393,7 @@ void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix, unsig
break;
+ case WRITE_6:
case WRITE_10:
case WRITE_12:
case WRITE_16:
@@ -475,8 +479,9 @@ int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_s
error:
kunmap_atomic(sdt, KM_USER0);
- sd_printk(KERN_ERR, sdkp, "%s: virt %u, phys %u, ref %u\n",
- __func__, virt, phys, be32_to_cpu(sdt->ref_tag));
+ sd_printk(KERN_ERR, sdkp, "%s: virt %u, phys %u, ref %u, app %4x\n",
+ __func__, virt, phys, be32_to_cpu(sdt->ref_tag),
+ be16_to_cpu(sdt->app_tag));
return -EIO;
}
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 7f0df29f3a64..e946e05db7f7 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -526,7 +526,7 @@ static int ses_intf_add(struct device *cdev,
if (!scomp)
goto err_free;
- edev = enclosure_register(cdev->parent, sdev->sdev_gendev.bus_id,
+ edev = enclosure_register(cdev->parent, dev_name(&sdev->sdev_gendev),
components, &ses_enclosure_callbacks);
if (IS_ERR(edev)) {
err = PTR_ERR(edev);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 5103855242ae..8f0bd3f7a59f 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1669,6 +1669,8 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd)
md->pages = req_schp->pages;
md->page_order = req_schp->page_order;
md->nr_entries = req_schp->k_use_sg;
+ md->offset = 0;
+ md->null_mapped = hp->dxferp ? 0 : 1;
}
if (iov_count)
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index 31fe6051c799..0807b260268b 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -297,7 +297,7 @@ out:
return err;
}
-static void __exit sgiwd93_remove(struct platform_device *pdev)
+static int __exit sgiwd93_remove(struct platform_device *pdev)
{
struct Scsi_Host *host = platform_get_drvdata(pdev);
struct ip22_hostdata *hdata = (struct ip22_hostdata *) host->hostdata;
@@ -307,6 +307,7 @@ static void __exit sgiwd93_remove(struct platform_device *pdev)
free_irq(pd->irq, host);
dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma);
scsi_host_put(host);
+ return 0;
}
static struct platform_driver sgiwd93_driver = {
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index d63d229e2323..6dc8b846c112 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -102,7 +102,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
struct NCR_700_Host_Parameters *hostdata =
kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
- printk(KERN_NOTICE "sim710: %s\n", dev->bus_id);
+ printk(KERN_NOTICE "sim710: %s\n", dev_name(dev));
printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n",
irq, clock, base_addr, scsi_id);
@@ -305,7 +305,7 @@ sim710_eisa_probe(struct device *dev)
scsi_id = ffs(val) - 1;
if(scsi_id > 7 || (val & ~(1<<scsi_id)) != 0) {
- printk(KERN_ERR "sim710.c, EISA card %s has incorrect scsi_id, setting to 7\n", dev->bus_id);
+ printk(KERN_ERR "sim710.c, EISA card %s has incorrect scsi_id, setting to 7\n", dev_name(dev));
scsi_id = 7;
}
} else {
diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c
index 2bbef4c45a0d..77f0b2cdaa94 100644
--- a/drivers/scsi/sni_53c710.c
+++ b/drivers/scsi/sni_53c710.c
@@ -78,8 +78,7 @@ static int __init snirm710_probe(struct platform_device *dev)
base = res->start;
hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
if (!hostdata) {
- printk(KERN_ERR "%s: Failed to allocate host data\n",
- dev->dev.bus_id);
+ dev_printk(KERN_ERR, dev, "Failed to allocate host data\n");
return -ENOMEM;
}
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 7f3f317ee6ca..c6f19ee8f2cb 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -17,7 +17,7 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
-static const char *verstr = "20080504";
+static const char *verstr = "20081215";
#include <linux/module.h>
@@ -182,18 +182,16 @@ static struct scsi_tape **scsi_tapes = NULL;
static int modes_defined;
-static struct st_buffer *new_tape_buffer(int, int, int);
static int enlarge_buffer(struct st_buffer *, int, int);
static void clear_buffer(struct st_buffer *);
static void normalize_buffer(struct st_buffer *);
static int append_to_buffer(const char __user *, struct st_buffer *, int);
static int from_buffer(struct st_buffer *, char __user *, int);
static void move_buffer_data(struct st_buffer *, int);
-static void buf_to_sg(struct st_buffer *, unsigned int);
-static int sgl_map_user_pages(struct scatterlist *, const unsigned int,
+static int sgl_map_user_pages(struct st_buffer *, const unsigned int,
unsigned long, size_t, int);
-static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int);
+static int sgl_unmap_user_pages(struct st_buffer *, const unsigned int, int);
static int st_probe(struct device *);
static int st_remove(struct device *);
@@ -435,22 +433,6 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
return (-EIO);
}
-
-/* Wakeup from interrupt */
-static void st_sleep_done(void *data, char *sense, int result, int resid)
-{
- struct st_request *SRpnt = data;
- struct scsi_tape *STp = SRpnt->stp;
-
- memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE);
- (STp->buffer)->cmdstat.midlevel_result = SRpnt->result = result;
- (STp->buffer)->cmdstat.residual = resid;
- DEB( STp->write_pending = 0; )
-
- if (SRpnt->waiting)
- complete(SRpnt->waiting);
-}
-
static struct st_request *st_allocate_request(struct scsi_tape *stp)
{
struct st_request *streq;
@@ -475,6 +457,63 @@ static void st_release_request(struct st_request *streq)
kfree(streq);
}
+static void st_scsi_execute_end(struct request *req, int uptodate)
+{
+ struct st_request *SRpnt = req->end_io_data;
+ struct scsi_tape *STp = SRpnt->stp;
+
+ STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors;
+ STp->buffer->cmdstat.residual = req->data_len;
+
+ if (SRpnt->waiting)
+ complete(SRpnt->waiting);
+
+ blk_rq_unmap_user(SRpnt->bio);
+ __blk_put_request(req->q, req);
+}
+
+static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
+ int data_direction, void *buffer, unsigned bufflen,
+ int timeout, int retries)
+{
+ struct request *req;
+ struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data;
+ int err = 0;
+ int write = (data_direction == DMA_TO_DEVICE);
+
+ req = blk_get_request(SRpnt->stp->device->request_queue, write,
+ GFP_KERNEL);
+ if (!req)
+ return DRIVER_ERROR << 24;
+
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ req->cmd_flags |= REQ_QUIET;
+
+ mdata->null_mapped = 1;
+
+ if (bufflen) {
+ err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen,
+ GFP_KERNEL);
+ if (err) {
+ blk_put_request(req);
+ return DRIVER_ERROR << 24;
+ }
+ }
+
+ SRpnt->bio = req->bio;
+ req->cmd_len = COMMAND_SIZE(cmd[0]);
+ memset(req->cmd, 0, BLK_MAX_CDB);
+ memcpy(req->cmd, cmd, req->cmd_len);
+ req->sense = SRpnt->sense;
+ req->sense_len = 0;
+ req->timeout = timeout;
+ req->retries = retries;
+ req->end_io_data = SRpnt;
+
+ blk_execute_rq_nowait(req->q, NULL, req, 1, st_scsi_execute_end);
+ return 0;
+}
+
/* Do the scsi command. Waits until command performed if do_wait is true.
Otherwise write_behind_check() is used to check that the command
has finished. */
@@ -483,6 +522,8 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd
int bytes, int direction, int timeout, int retries, int do_wait)
{
struct completion *waiting;
+ struct rq_map_data *mdata = &STp->buffer->map_data;
+ int ret;
/* if async, make sure there's no command outstanding */
if (!do_wait && ((STp->buffer)->last_SRpnt)) {
@@ -510,21 +551,27 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd
init_completion(waiting);
SRpnt->waiting = waiting;
- if (!STp->buffer->do_dio)
- buf_to_sg(STp->buffer, bytes);
+ if (STp->buffer->do_dio) {
+ mdata->nr_entries = STp->buffer->sg_segs;
+ mdata->pages = STp->buffer->mapped_pages;
+ } else {
+ mdata->nr_entries =
+ DIV_ROUND_UP(bytes, PAGE_SIZE << mdata->page_order);
+ STp->buffer->map_data.pages = STp->buffer->reserved_pages;
+ STp->buffer->map_data.offset = 0;
+ }
memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd));
STp->buffer->cmdstat.have_sense = 0;
STp->buffer->syscall_result = 0;
- if (scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), direction,
- &((STp->buffer)->sg[0]), bytes, (STp->buffer)->sg_segs,
- timeout, retries, SRpnt, st_sleep_done, GFP_KERNEL)) {
+ ret = st_scsi_execute(SRpnt, cmd, direction, NULL, bytes, timeout,
+ retries);
+ if (ret) {
/* could not allocate the buffer or request was too large */
(STp->buffer)->syscall_result = (-EBUSY);
(STp->buffer)->last_SRpnt = NULL;
- }
- else if (do_wait) {
+ } else if (do_wait) {
wait_for_completion(waiting);
SRpnt->waiting = NULL;
(STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);
@@ -533,28 +580,6 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd
return SRpnt;
}
-static int st_scsi_kern_execute(struct st_request *streq,
- const unsigned char *cmd, int data_direction,
- void *buffer, unsigned bufflen, int timeout,
- int retries)
-{
- struct scsi_tape *stp = streq->stp;
- int ret, resid;
-
- stp->buffer->cmdstat.have_sense = 0;
- memcpy(streq->cmd, cmd, sizeof(streq->cmd));
-
- ret = scsi_execute(stp->device, cmd, data_direction, buffer, bufflen,
- streq->sense, timeout, retries, 0, &resid);
- if (driver_byte(ret) & DRIVER_ERROR)
- return -EBUSY;
-
- stp->buffer->cmdstat.midlevel_result = streq->result = ret;
- stp->buffer->cmdstat.residual = resid;
- stp->buffer->syscall_result = st_chk_result(stp, streq);
-
- return 0;
-}
/* Handle the write-behind checking (waits for completion). Returns -ENOSPC if
write has been correct but EOM early warning reached, -EIO if write ended in
@@ -627,7 +652,6 @@ static int cross_eof(struct scsi_tape * STp, int forward)
{
struct st_request *SRpnt;
unsigned char cmd[MAX_COMMAND_SIZE];
- int ret;
cmd[0] = SPACE;
cmd[1] = 0x01; /* Space FileMarks */
@@ -641,26 +665,20 @@ static int cross_eof(struct scsi_tape * STp, int forward)
DEBC(printk(ST_DEB_MSG "%s: Stepping over filemark %s.\n",
tape_name(STp), forward ? "forward" : "backward"));
- SRpnt = st_allocate_request(STp);
+ SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
+ STp->device->request_queue->rq_timeout,
+ MAX_RETRIES, 1);
if (!SRpnt)
- return STp->buffer->syscall_result;
-
- ret = st_scsi_kern_execute(SRpnt, cmd, DMA_NONE, NULL, 0,
- STp->device->request_queue->rq_timeout,
- MAX_RETRIES);
- if (ret)
- goto out;
+ return (STp->buffer)->syscall_result;
- ret = STp->buffer->syscall_result;
+ st_release_request(SRpnt);
+ SRpnt = NULL;
if ((STp->buffer)->cmdstat.midlevel_result != 0)
printk(KERN_ERR "%s: Stepping over filemark %s failed.\n",
tape_name(STp), forward ? "forward" : "backward");
-out:
- st_release_request(SRpnt);
-
- return ret;
+ return (STp->buffer)->syscall_result;
}
@@ -881,24 +899,21 @@ static int test_ready(struct scsi_tape *STp, int do_wait)
int attentions, waits, max_wait, scode;
int retval = CHKRES_READY, new_session = 0;
unsigned char cmd[MAX_COMMAND_SIZE];
- struct st_request *SRpnt;
+ struct st_request *SRpnt = NULL;
struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
- SRpnt = st_allocate_request(STp);
- if (!SRpnt)
- return STp->buffer->syscall_result;
-
max_wait = do_wait ? ST_BLOCK_SECONDS : 0;
for (attentions=waits=0; ; ) {
memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = TEST_UNIT_READY;
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
+ STp->long_timeout, MAX_READY_RETRIES, 1);
- retval = st_scsi_kern_execute(SRpnt, cmd, DMA_NONE, NULL, 0,
- STp->long_timeout,
- MAX_READY_RETRIES);
- if (retval)
+ if (!SRpnt) {
+ retval = (STp->buffer)->syscall_result;
break;
+ }
if (cmdstatp->have_sense) {
@@ -942,8 +957,8 @@ static int test_ready(struct scsi_tape *STp, int do_wait)
break;
}
- st_release_request(SRpnt);
-
+ if (SRpnt != NULL)
+ st_release_request(SRpnt);
return retval;
}
@@ -1020,24 +1035,17 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
}
}
- SRpnt = st_allocate_request(STp);
- if (!SRpnt) {
- retval = STp->buffer->syscall_result;
- goto err_out;
- }
-
if (STp->omit_blklims)
STp->min_block = STp->max_block = (-1);
else {
memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
cmd[0] = READ_BLOCK_LIMITS;
- retval = st_scsi_kern_execute(SRpnt, cmd, DMA_FROM_DEVICE,
- STp->buffer->b_data, 6,
- STp->device->request_queue->rq_timeout,
- MAX_READY_RETRIES);
- if (retval) {
- st_release_request(SRpnt);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, DMA_FROM_DEVICE,
+ STp->device->request_queue->rq_timeout,
+ MAX_READY_RETRIES, 1);
+ if (!SRpnt) {
+ retval = (STp->buffer)->syscall_result;
goto err_out;
}
@@ -1061,12 +1069,11 @@ static int check_tape(struct scsi_tape *STp, struct file *filp)
cmd[0] = MODE_SENSE;
cmd[4] = 12;
- retval = st_scsi_kern_execute(SRpnt, cmd, DMA_FROM_DEVICE,
- STp->buffer->b_data, 12,
- STp->device->request_queue->rq_timeout,
- MAX_READY_RETRIES);
- if (retval) {
- st_release_request(SRpnt);
+ SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, DMA_FROM_DEVICE,
+ STp->device->request_queue->rq_timeout,
+ MAX_READY_RETRIES, 1);
+ if (!SRpnt) {
+ retval = (STp->buffer)->syscall_result;
goto err_out;
}
@@ -1296,17 +1303,11 @@ static int st_flush(struct file *filp, fl_owner_t id)
cmd[0] = WRITE_FILEMARKS;
cmd[4] = 1 + STp->two_fm;
- SRpnt = st_allocate_request(STp);
+ SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
+ STp->device->request_queue->rq_timeout,
+ MAX_WRITE_RETRIES, 1);
if (!SRpnt) {
- result = STp->buffer->syscall_result;
- goto out;
- }
-
- result = st_scsi_kern_execute(SRpnt, cmd, DMA_NONE, NULL, 0,
- STp->device->request_queue->rq_timeout,
- MAX_WRITE_RETRIES);
- if (result) {
- st_release_request(SRpnt);
+ result = (STp->buffer)->syscall_result;
goto out;
}
@@ -1471,8 +1472,8 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
if (i && ((unsigned long)buf & queue_dma_alignment(
STp->device->request_queue)) == 0) {
- i = sgl_map_user_pages(&(STbp->sg[0]), STbp->use_sg,
- (unsigned long)buf, count, (is_read ? READ : WRITE));
+ i = sgl_map_user_pages(STbp, STbp->use_sg, (unsigned long)buf,
+ count, (is_read ? READ : WRITE));
if (i > 0) {
STbp->do_dio = i;
STbp->buffer_bytes = 0; /* can be used as transfer counter */
@@ -1480,7 +1481,6 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
else
STbp->do_dio = 0; /* fall back to buffering with any error */
STbp->sg_segs = STbp->do_dio;
- STbp->frp_sg_current = 0;
DEB(
if (STbp->do_dio) {
STp->nbr_dio++;
@@ -1526,7 +1526,7 @@ static void release_buffering(struct scsi_tape *STp, int is_read)
STbp = STp->buffer;
if (STbp->do_dio) {
- sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, is_read);
+ sgl_unmap_user_pages(STbp, STbp->do_dio, is_read);
STbp->do_dio = 0;
STbp->sg_segs = 0;
}
@@ -2372,7 +2372,6 @@ static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs)
{
unsigned char cmd[MAX_COMMAND_SIZE];
struct st_request *SRpnt;
- int ret;
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SENSE;
@@ -2381,17 +2380,14 @@ static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs)
cmd[2] = page;
cmd[4] = 255;
- SRpnt = st_allocate_request(STp);
- if (!SRpnt)
- return STp->buffer->syscall_result;
+ SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_FROM_DEVICE,
+ STp->device->request_queue->rq_timeout, 0, 1);
+ if (SRpnt == NULL)
+ return (STp->buffer)->syscall_result;
- ret = st_scsi_kern_execute(SRpnt, cmd, DMA_FROM_DEVICE,
- STp->buffer->b_data, cmd[4],
- STp->device->request_queue->rq_timeout,
- MAX_RETRIES);
st_release_request(SRpnt);
- return ret ? : STp->buffer->syscall_result;
+ return STp->buffer->syscall_result;
}
@@ -2399,9 +2395,10 @@ static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs)
in the buffer is correctly formatted. The long timeout is used if slow is non-zero. */
static int write_mode_page(struct scsi_tape *STp, int page, int slow)
{
- int pgo, timeout, ret = 0;
+ int pgo;
unsigned char cmd[MAX_COMMAND_SIZE];
struct st_request *SRpnt;
+ int timeout;
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = MODE_SELECT;
@@ -2415,21 +2412,16 @@ static int write_mode_page(struct scsi_tape *STp, int page, int slow)
(STp->buffer)->b_data[MH_OFF_DEV_SPECIFIC] &= ~MH_BIT_WP;
(STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR;
- SRpnt = st_allocate_request(STp);
- if (!SRpnt)
- return ret;
-
- timeout = slow ? STp->long_timeout :
- STp->device->request_queue->rq_timeout;
-
- ret = st_scsi_kern_execute(SRpnt, cmd, DMA_TO_DEVICE,
- STp->buffer->b_data, cmd[4], timeout, 0);
- if (!ret)
- ret = STp->buffer->syscall_result;
+ timeout = slow ?
+ STp->long_timeout : STp->device->request_queue->rq_timeout;
+ SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_TO_DEVICE,
+ timeout, 0, 1);
+ if (SRpnt == NULL)
+ return (STp->buffer)->syscall_result;
st_release_request(SRpnt);
- return ret;
+ return STp->buffer->syscall_result;
}
@@ -2547,16 +2539,13 @@ static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_cod
printk(ST_DEB_MSG "%s: Loading tape.\n", name);
);
- SRpnt = st_allocate_request(STp);
+ SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
+ timeout, MAX_RETRIES, 1);
if (!SRpnt)
- return STp->buffer->syscall_result;
-
- retval = st_scsi_kern_execute(SRpnt, cmd, DMA_NONE, NULL, 0, timeout,
- MAX_RETRIES);
- if (retval)
- goto out;
+ return (STp->buffer)->syscall_result;
retval = (STp->buffer)->syscall_result;
+ st_release_request(SRpnt);
if (!retval) { /* SCSI command successful */
@@ -2575,8 +2564,6 @@ static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_cod
STps = &(STp->ps[STp->partition]);
STps->drv_file = STps->drv_block = (-1);
}
-out:
- st_release_request(SRpnt);
return retval;
}
@@ -2852,15 +2839,12 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
return (-ENOSYS);
}
- SRpnt = st_allocate_request(STp);
+ SRpnt = st_do_scsi(NULL, STp, cmd, datalen, direction,
+ timeout, MAX_RETRIES, 1);
if (!SRpnt)
return (STp->buffer)->syscall_result;
- ioctl_result = st_scsi_kern_execute(SRpnt, cmd, direction,
- STp->buffer->b_data, datalen,
- timeout, MAX_RETRIES);
- if (!ioctl_result)
- ioctl_result = (STp->buffer)->syscall_result;
+ ioctl_result = (STp->buffer)->syscall_result;
if (!ioctl_result) { /* SCSI command successful */
st_release_request(SRpnt);
@@ -3022,17 +3006,11 @@ static int get_location(struct scsi_tape *STp, unsigned int *block, int *partiti
if (!logical && !STp->scsi2_logical)
scmd[1] = 1;
}
-
- SRpnt = st_allocate_request(STp);
+ SRpnt = st_do_scsi(NULL, STp, scmd, 20, DMA_FROM_DEVICE,
+ STp->device->request_queue->rq_timeout,
+ MAX_READY_RETRIES, 1);
if (!SRpnt)
- return STp->buffer->syscall_result;
-
- result = st_scsi_kern_execute(SRpnt, scmd, DMA_FROM_DEVICE,
- STp->buffer->b_data, 20,
- STp->device->request_queue->rq_timeout,
- MAX_READY_RETRIES);
- if (result)
- goto out;
+ return (STp->buffer)->syscall_result;
if ((STp->buffer)->syscall_result != 0 ||
(STp->device->scsi_level >= SCSI_2 &&
@@ -3060,7 +3038,6 @@ static int get_location(struct scsi_tape *STp, unsigned int *block, int *partiti
DEBC(printk(ST_DEB_MSG "%s: Got tape pos. blk %d part %d.\n", name,
*block, *partition));
}
-out:
st_release_request(SRpnt);
SRpnt = NULL;
@@ -3135,14 +3112,10 @@ static int set_location(struct scsi_tape *STp, unsigned int block, int partition
timeout = STp->device->request_queue->rq_timeout;
}
- SRpnt = st_allocate_request(STp);
+ SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE,
+ timeout, MAX_READY_RETRIES, 1);
if (!SRpnt)
- return STp->buffer->syscall_result;
-
- result = st_scsi_kern_execute(SRpnt, scmd, DMA_NONE, NULL, 0,
- timeout, MAX_READY_RETRIES);
- if (result)
- goto out;
+ return (STp->buffer)->syscall_result;
STps->drv_block = STps->drv_file = (-1);
STps->eof = ST_NOEOF;
@@ -3167,7 +3140,7 @@ static int set_location(struct scsi_tape *STp, unsigned int block, int partition
STps->drv_block = STps->drv_file = 0;
result = 0;
}
-out:
+
st_release_request(SRpnt);
SRpnt = NULL;
@@ -3696,38 +3669,34 @@ static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a
/* Try to allocate a new tape buffer. Calling function must not hold
dev_arr_lock. */
-static struct st_buffer *
- new_tape_buffer(int from_initialization, int need_dma, int max_sg)
+static struct st_buffer *new_tape_buffer(int need_dma, int max_sg)
{
- int i, got = 0;
- gfp_t priority;
struct st_buffer *tb;
- if (from_initialization)
- priority = GFP_ATOMIC;
- else
- priority = GFP_KERNEL;
-
- i = sizeof(struct st_buffer) + (max_sg - 1) * sizeof(struct scatterlist) +
- max_sg * sizeof(struct st_buf_fragment);
- tb = kzalloc(i, priority);
+ tb = kzalloc(sizeof(struct st_buffer), GFP_ATOMIC);
if (!tb) {
printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n");
return NULL;
}
- tb->frp_segs = tb->orig_frp_segs = 0;
+ tb->frp_segs = 0;
tb->use_sg = max_sg;
- tb->frp = (struct st_buf_fragment *)(&(tb->sg[0]) + max_sg);
-
tb->dma = need_dma;
- tb->buffer_size = got;
- sg_init_table(tb->sg, max_sg);
+ tb->buffer_size = 0;
+
+ tb->reserved_pages = kzalloc(max_sg * sizeof(struct page *),
+ GFP_ATOMIC);
+ if (!tb->reserved_pages) {
+ kfree(tb);
+ return NULL;
+ }
return tb;
}
/* Try to allocate enough space in the tape buffer */
+#define ST_MAX_ORDER 6
+
static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dma)
{
int segs, nbr, max_segs, b_size, order, got;
@@ -3747,33 +3716,45 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm
priority = GFP_KERNEL | __GFP_NOWARN;
if (need_dma)
priority |= GFP_DMA;
- for (b_size = PAGE_SIZE, order=0; order <= 6 &&
- b_size < new_size - STbuffer->buffer_size;
- order++, b_size *= 2)
- ; /* empty */
+
+ if (STbuffer->cleared)
+ priority |= __GFP_ZERO;
+
+ if (STbuffer->frp_segs) {
+ order = STbuffer->map_data.page_order;
+ b_size = PAGE_SIZE << order;
+ } else {
+ for (b_size = PAGE_SIZE, order = 0;
+ order < ST_MAX_ORDER && b_size < new_size;
+ order++, b_size *= 2)
+ ; /* empty */
+ }
+ if (max_segs * (PAGE_SIZE << order) < new_size) {
+ if (order == ST_MAX_ORDER)
+ return 0;
+ normalize_buffer(STbuffer);
+ return enlarge_buffer(STbuffer, new_size, need_dma);
+ }
for (segs = STbuffer->frp_segs, got = STbuffer->buffer_size;
segs < max_segs && got < new_size;) {
- STbuffer->frp[segs].page = alloc_pages(priority, order);
- if (STbuffer->frp[segs].page == NULL) {
- if (new_size - got <= (max_segs - segs) * b_size / 2) {
- b_size /= 2; /* Large enough for the rest of the buffers */
- order--;
- continue;
- }
+ struct page *page;
+
+ page = alloc_pages(priority, order);
+ if (!page) {
DEB(STbuffer->buffer_size = got);
normalize_buffer(STbuffer);
return 0;
}
- STbuffer->frp[segs].length = b_size;
+
STbuffer->frp_segs += 1;
got += b_size;
STbuffer->buffer_size = got;
- if (STbuffer->cleared)
- memset(page_address(STbuffer->frp[segs].page), 0, b_size);
+ STbuffer->reserved_pages[segs] = page;
segs++;
}
- STbuffer->b_data = page_address(STbuffer->frp[0].page);
+ STbuffer->b_data = page_address(STbuffer->reserved_pages[0]);
+ STbuffer->map_data.page_order = order;
return 1;
}
@@ -3785,7 +3766,8 @@ static void clear_buffer(struct st_buffer * st_bp)
int i;
for (i=0; i < st_bp->frp_segs; i++)
- memset(page_address(st_bp->frp[i].page), 0, st_bp->frp[i].length);
+ memset(page_address(st_bp->reserved_pages[i]), 0,
+ PAGE_SIZE << st_bp->map_data.page_order);
st_bp->cleared = 1;
}
@@ -3793,16 +3775,16 @@ static void clear_buffer(struct st_buffer * st_bp)
/* Release the extra buffer */
static void normalize_buffer(struct st_buffer * STbuffer)
{
- int i, order;
+ int i, order = STbuffer->map_data.page_order;
- for (i = STbuffer->orig_frp_segs; i < STbuffer->frp_segs; i++) {
- order = get_order(STbuffer->frp[i].length);
- __free_pages(STbuffer->frp[i].page, order);
- STbuffer->buffer_size -= STbuffer->frp[i].length;
+ for (i = 0; i < STbuffer->frp_segs; i++) {
+ __free_pages(STbuffer->reserved_pages[i], order);
+ STbuffer->buffer_size -= (PAGE_SIZE << order);
}
- STbuffer->frp_segs = STbuffer->orig_frp_segs;
- STbuffer->frp_sg_current = 0;
+ STbuffer->frp_segs = 0;
STbuffer->sg_segs = 0;
+ STbuffer->map_data.page_order = 0;
+ STbuffer->map_data.offset = 0;
}
@@ -3811,18 +3793,19 @@ static void normalize_buffer(struct st_buffer * STbuffer)
static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count)
{
int i, cnt, res, offset;
+ int length = PAGE_SIZE << st_bp->map_data.page_order;
for (i = 0, offset = st_bp->buffer_bytes;
- i < st_bp->frp_segs && offset >= st_bp->frp[i].length; i++)
- offset -= st_bp->frp[i].length;
+ i < st_bp->frp_segs && offset >= length; i++)
+ offset -= length;
if (i == st_bp->frp_segs) { /* Should never happen */
printk(KERN_WARNING "st: append_to_buffer offset overflow.\n");
return (-EIO);
}
for (; i < st_bp->frp_segs && do_count > 0; i++) {
- cnt = st_bp->frp[i].length - offset < do_count ?
- st_bp->frp[i].length - offset : do_count;
- res = copy_from_user(page_address(st_bp->frp[i].page) + offset, ubp, cnt);
+ struct page *page = st_bp->reserved_pages[i];
+ cnt = length - offset < do_count ? length - offset : do_count;
+ res = copy_from_user(page_address(page) + offset, ubp, cnt);
if (res)
return (-EFAULT);
do_count -= cnt;
@@ -3842,18 +3825,19 @@ static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, in
static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count)
{
int i, cnt, res, offset;
+ int length = PAGE_SIZE << st_bp->map_data.page_order;
for (i = 0, offset = st_bp->read_pointer;
- i < st_bp->frp_segs && offset >= st_bp->frp[i].length; i++)
- offset -= st_bp->frp[i].length;
+ i < st_bp->frp_segs && offset >= length; i++)
+ offset -= length;
if (i == st_bp->frp_segs) { /* Should never happen */
printk(KERN_WARNING "st: from_buffer offset overflow.\n");
return (-EIO);
}
for (; i < st_bp->frp_segs && do_count > 0; i++) {
- cnt = st_bp->frp[i].length - offset < do_count ?
- st_bp->frp[i].length - offset : do_count;
- res = copy_to_user(ubp, page_address(st_bp->frp[i].page) + offset, cnt);
+ struct page *page = st_bp->reserved_pages[i];
+ cnt = length - offset < do_count ? length - offset : do_count;
+ res = copy_to_user(ubp, page_address(page) + offset, cnt);
if (res)
return (-EFAULT);
do_count -= cnt;
@@ -3874,6 +3858,7 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset)
{
int src_seg, dst_seg, src_offset = 0, dst_offset;
int count, total;
+ int length = PAGE_SIZE << st_bp->map_data.page_order;
if (offset == 0)
return;
@@ -3881,24 +3866,26 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset)
total=st_bp->buffer_bytes - offset;
for (src_seg=0; src_seg < st_bp->frp_segs; src_seg++) {
src_offset = offset;
- if (src_offset < st_bp->frp[src_seg].length)
+ if (src_offset < length)
break;
- offset -= st_bp->frp[src_seg].length;
+ offset -= length;
}
st_bp->buffer_bytes = st_bp->read_pointer = total;
for (dst_seg=dst_offset=0; total > 0; ) {
- count = min(st_bp->frp[dst_seg].length - dst_offset,
- st_bp->frp[src_seg].length - src_offset);
- memmove(page_address(st_bp->frp[dst_seg].page) + dst_offset,
- page_address(st_bp->frp[src_seg].page) + src_offset, count);
+ struct page *dpage = st_bp->reserved_pages[dst_seg];
+ struct page *spage = st_bp->reserved_pages[src_seg];
+
+ count = min(length - dst_offset, length - src_offset);
+ memmove(page_address(dpage) + dst_offset,
+ page_address(spage) + src_offset, count);
src_offset += count;
- if (src_offset >= st_bp->frp[src_seg].length) {
+ if (src_offset >= length) {
src_seg++;
src_offset = 0;
}
dst_offset += count;
- if (dst_offset >= st_bp->frp[dst_seg].length) {
+ if (dst_offset >= length) {
dst_seg++;
dst_offset = 0;
}
@@ -3906,32 +3893,6 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset)
}
}
-
-/* Fill the s/g list up to the length required for this transfer */
-static void buf_to_sg(struct st_buffer *STbp, unsigned int length)
-{
- int i;
- unsigned int count;
- struct scatterlist *sg;
- struct st_buf_fragment *frp;
-
- if (length == STbp->frp_sg_current)
- return; /* work already done */
-
- sg = &(STbp->sg[0]);
- frp = STbp->frp;
- for (i=count=0; count < length; i++) {
- if (length - count > frp[i].length)
- sg_set_page(&sg[i], frp[i].page, frp[i].length, 0);
- else
- sg_set_page(&sg[i], frp[i].page, length - count, 0);
- count += sg[i].length;
- }
- STbp->sg_segs = i;
- STbp->frp_sg_current = length;
-}
-
-
/* Validate the options from command line or module parameters */
static void validate_options(void)
{
@@ -4026,7 +3987,7 @@ static int st_probe(struct device *dev)
SDp->request_queue->max_phys_segments);
if (st_max_sg_segs < i)
i = st_max_sg_segs;
- buffer = new_tape_buffer(1, (SDp->host)->unchecked_isa_dma, i);
+ buffer = new_tape_buffer((SDp->host)->unchecked_isa_dma, i);
if (buffer == NULL) {
printk(KERN_ERR
"st: Can't allocate new tape buffer. Device not attached.\n");
@@ -4280,8 +4241,8 @@ static void scsi_tape_release(struct kref *kref)
tpnt->device = NULL;
if (tpnt->buffer) {
- tpnt->buffer->orig_frp_segs = 0;
normalize_buffer(tpnt->buffer);
+ kfree(tpnt->buffer->reserved_pages);
kfree(tpnt->buffer);
}
@@ -4567,14 +4528,16 @@ out:
}
/* The following functions may be useful for a larger audience. */
-static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages,
- unsigned long uaddr, size_t count, int rw)
+static int sgl_map_user_pages(struct st_buffer *STbp,
+ const unsigned int max_pages, unsigned long uaddr,
+ size_t count, int rw)
{
unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT;
unsigned long start = uaddr >> PAGE_SHIFT;
const int nr_pages = end - start;
int res, i, j;
struct page **pages;
+ struct rq_map_data *mdata = &STbp->map_data;
/* User attempted Overflow! */
if ((uaddr + count) < uaddr)
@@ -4616,24 +4579,11 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa
flush_dcache_page(pages[i]);
}
- /* Populate the scatter/gather list */
- sg_set_page(&sgl[0], pages[0], 0, uaddr & ~PAGE_MASK);
- if (nr_pages > 1) {
- sgl[0].length = PAGE_SIZE - sgl[0].offset;
- count -= sgl[0].length;
- for (i=1; i < nr_pages ; i++) {
- sg_set_page(&sgl[i], pages[i],
- count < PAGE_SIZE ? count : PAGE_SIZE, 0);;
- count -= PAGE_SIZE;
- }
- }
- else {
- sgl[0].length = count;
- }
+ mdata->offset = uaddr & ~PAGE_MASK;
+ mdata->page_order = 0;
+ STbp->mapped_pages = pages;
- kfree(pages);
return nr_pages;
-
out_unmap:
if (res > 0) {
for (j=0; j < res; j++)
@@ -4646,13 +4596,13 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa
/* And unmap them... */
-static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages,
- int dirtied)
+static int sgl_unmap_user_pages(struct st_buffer *STbp,
+ const unsigned int nr_pages, int dirtied)
{
int i;
for (i=0; i < nr_pages; i++) {
- struct page *page = sg_page(&sgl[i]);
+ struct page *page = STbp->mapped_pages[i];
if (dirtied)
SetPageDirty(page);
@@ -4661,6 +4611,8 @@ static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_p
*/
page_cache_release(page);
}
+ kfree(STbp->mapped_pages);
+ STbp->mapped_pages = NULL;
return 0;
}
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index b92712f95931..544dc6b1f548 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -29,6 +29,7 @@ struct st_request {
int result;
struct scsi_tape *stp;
struct completion *waiting;
+ struct bio *bio;
};
/* The tape buffer descriptor. */
@@ -44,20 +45,13 @@ struct st_buffer {
int syscall_result;
struct st_request *last_SRpnt;
struct st_cmdstatus cmdstat;
+ struct page **reserved_pages;
+ struct page **mapped_pages;
+ struct rq_map_data map_data;
unsigned char *b_data;
unsigned short use_sg; /* zero or max number of s/g segments for this adapter */
unsigned short sg_segs; /* number of segments in s/g list */
- unsigned short orig_frp_segs; /* number of segments allocated at first try */
unsigned short frp_segs; /* number of buffer segments */
- unsigned int frp_sg_current; /* driver buffer length currently in s/g list */
- struct st_buf_fragment *frp; /* the allocated buffer fragment list */
- struct scatterlist sg[1]; /* MUST BE last item */
-};
-
-/* The tape buffer fragment descriptor */
-struct st_buf_fragment {
- struct page *page;
- unsigned int length;
};
/* The tape mode definition */
diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c
index 3c4a300494a4..a8d61a62522e 100644
--- a/drivers/scsi/zalon.c
+++ b/drivers/scsi/zalon.c
@@ -137,8 +137,8 @@ zalon_probe(struct parisc_device *dev)
goto fail;
if (request_irq(dev->irq, ncr53c8xx_intr, IRQF_SHARED, "zalon", host)) {
- printk(KERN_ERR "%s: irq problem with %d, detaching\n ",
- dev->dev.bus_id, dev->irq);
+ dev_printk(KERN_ERR, dev, "irq problem with %d, detaching\n ",
+ dev->irq);
goto fail;
}
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index daa00567bc44..0d934bfbdd9b 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2839,6 +2839,8 @@ int __init early_serial_setup(struct uart_port *port)
p->flags = port->flags;
p->mapbase = port->mapbase;
p->private_data = port->private_data;
+ p->type = port->type;
+ p->line = port->line;
set_io_from_upio(p);
if (port->serial_in)
@@ -3123,7 +3125,7 @@ static int __init serial8250_init(void)
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
- printk(KERN_INFO "Serial: 8250/16550 driver"
+ printk(KERN_INFO "Serial: 8250/16550 driver, "
"%d ports, IRQ sharing %sabled\n", nr_uarts,
share_irqs ? "en" : "dis");
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index c088146b7513..2a3671233b15 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -602,6 +602,10 @@ static int pci_netmos_init(struct pci_dev *dev)
/* subdevice 0x00PS means <P> parallel, <S> serial */
unsigned int num_serial = dev->subsystem_device & 0xf;
+ if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
+ dev->subsystem_device == 0x0299)
+ return 0;
+
if (num_serial == 0)
return -ENODEV;
return num_serial;
@@ -3096,6 +3100,10 @@ static struct pci_device_id serial_pci_tbl[] = {
0,
pbn_b0_8_115200 },
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
+ PCI_VENDOR_ID_IBM, 0x0299,
+ 0, 0, pbn_b0_bt_2_115200 },
+
/*
* These entries match devices with class COMMUNICATION_SERIAL,
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index fde7f9ccf57e..bbcfc26a3b6d 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -270,6 +270,8 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "RSS0250", 0 },
/* SupraExpress 28.8 Data/Fax PnP modem */
{ "SUP1310", 0 },
+ /* SupraExpress 336i PnP Voice Modem */
+ { "SUP1381", 0 },
/* SupraExpress 33.6 Data/Fax PnP modem */
{ "SUP1421", 0 },
/* SupraExpress 33.6 Data/Fax PnP modem */
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index b695ab3142d8..3e525e38a5d9 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -457,7 +457,7 @@ config SERIAL_SAMSUNG
config SERIAL_SAMSUNG_UARTS
int
- depends on SERIAL_SAMSUNG
+ depends on ARM && PLAT_S3C
default 2 if ARCH_S3C2400
default 4 if ARCH_S3C64XX || CPU_S3C2443
default 3
@@ -1320,13 +1320,30 @@ config SERIAL_NETX_CONSOLE
config SERIAL_OF_PLATFORM
tristate "Serial port on Open Firmware platform bus"
depends on PPC_OF
- depends on SERIAL_8250
+ depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
help
If you have a PowerPC based system that has serial ports
on a platform specific bus, you should enable this option.
Currently, only 8250 compatible ports are supported, but
others can easily be added.
+config SERIAL_OF_PLATFORM_NWPSERIAL
+ tristate "NWP serial port driver"
+ depends on PPC_OF && PPC_DCR
+ select SERIAL_OF_PLATFORM
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_CORE
+ help
+ This driver supports the cell network processor nwp serial
+ device.
+
+config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
+ bool "Console on NWP serial port"
+ depends on SERIAL_OF_PLATFORM_NWPSERIAL=y
+ select SERIAL_CORE_CONSOLE
+ help
+ Support for Console on the NWP serial ports.
+
config SERIAL_QE
tristate "Freescale QUICC Engine serial port support"
depends on QUICC_ENGINE
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index dfe775ac45b2..8844c0a03929 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
+obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index d5efd6c77904..89362d733d62 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -579,7 +579,7 @@ static void atmel_tx_dma(struct uart_port *port)
/* disable PDC transmit */
UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
- if (!uart_circ_empty(xmit)) {
+ if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
dma_sync_single_for_device(port->dev,
pdc->dma_addr,
pdc->dma_size,
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index 8b2c619a09f2..e642c22c80e2 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -1203,7 +1203,7 @@ static void e100_disable_txdma_channel(struct e100_serial *info)
unsigned long flags;
/* Disable output DMA channel for the serial port in question
- * ( set to something other then serialX)
+ * ( set to something other than serialX)
*/
local_irq_save(flags);
DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line));
@@ -1266,7 +1266,7 @@ static void e100_disable_rxdma_channel(struct e100_serial *info)
unsigned long flags;
/* Disable input DMA channel for the serial port in question
- * ( set to something other then serialX)
+ * ( set to something other than serialX)
*/
local_irq_save(flags);
if (info->line == 0) {
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
index b7584ca55ade..e6390d023634 100644
--- a/drivers/serial/jsm/jsm_neo.c
+++ b/drivers/serial/jsm/jsm_neo.c
@@ -577,9 +577,6 @@ static void neo_parse_modem(struct jsm_channel *ch, u8 signals)
jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev,
"neo_parse_modem: port: %d msignals: %x\n", ch->ch_portnum, msignals);
- if (!ch)
- return;
-
/* Scrub off lower bits. They signify delta's, which I don't care about */
/* Keep DDCD and DDSR though */
msignals &= 0xf8;
diff --git a/drivers/serial/nwpserial.c b/drivers/serial/nwpserial.c
new file mode 100644
index 000000000000..32f3eaf0d262
--- /dev/null
+++ b/drivers/serial/nwpserial.c
@@ -0,0 +1,475 @@
+/*
+ * Serial Port driver for a NWP uart device
+ *
+ * Copyright (C) 2008 IBM Corp., Benjamin Krill <ben@codiert.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.
+ *
+ */
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/irqreturn.h>
+#include <linux/mutex.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/nwpserial.h>
+#include <asm/prom.h>
+#include <asm/dcr.h>
+
+#define NWPSERIAL_NR 2
+
+#define NWPSERIAL_STATUS_RXVALID 0x1
+#define NWPSERIAL_STATUS_TXFULL 0x2
+
+struct nwpserial_port {
+ struct uart_port port;
+ dcr_host_t dcr_host;
+ unsigned int ier;
+ unsigned int mcr;
+};
+
+static DEFINE_MUTEX(nwpserial_mutex);
+static struct nwpserial_port nwpserial_ports[NWPSERIAL_NR];
+
+static void wait_for_bits(struct nwpserial_port *up, int bits)
+{
+ unsigned int status, tmout = 10000;
+
+ /* Wait up to 10ms for the character(s) to be sent. */
+ do {
+ status = dcr_read(up->dcr_host, UART_LSR);
+
+ if (--tmout == 0)
+ break;
+ udelay(1);
+ } while ((status & bits) != bits);
+}
+
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
+static void nwpserial_console_putchar(struct uart_port *port, int c)
+{
+ struct nwpserial_port *up;
+ up = container_of(port, struct nwpserial_port, port);
+ /* check if tx buffer is full */
+ wait_for_bits(up, UART_LSR_THRE);
+ dcr_write(up->dcr_host, UART_TX, c);
+ up->port.icount.tx++;
+}
+
+static void
+nwpserial_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct nwpserial_port *up = &nwpserial_ports[co->index];
+ unsigned long flags;
+ int locked = 1;
+
+ if (oops_in_progress)
+ locked = spin_trylock_irqsave(&up->port.lock, flags);
+ else
+ spin_lock_irqsave(&up->port.lock, flags);
+
+ /* save and disable interrupt */
+ up->ier = dcr_read(up->dcr_host, UART_IER);
+ dcr_write(up->dcr_host, UART_IER, up->ier & ~UART_IER_RDI);
+
+ uart_console_write(&up->port, s, count, nwpserial_console_putchar);
+
+ /* wait for transmitter to become emtpy */
+ while ((dcr_read(up->dcr_host, UART_LSR) & UART_LSR_THRE) == 0)
+ cpu_relax();
+
+ /* restore interrupt state */
+ dcr_write(up->dcr_host, UART_IER, up->ier);
+
+ if (locked)
+ spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static struct uart_driver nwpserial_reg;
+static struct console nwpserial_console = {
+ .name = "ttySQ",
+ .write = nwpserial_console_write,
+ .device = uart_console_device,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &nwpserial_reg,
+};
+#define NWPSERIAL_CONSOLE (&nwpserial_console)
+#else
+#define NWPSERIAL_CONSOLE NULL
+#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
+
+/**************************************************************************/
+
+static int nwpserial_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+static void nwpserial_release_port(struct uart_port *port)
+{
+ /* N/A */
+}
+
+static void nwpserial_config_port(struct uart_port *port, int flags)
+{
+ port->type = PORT_NWPSERIAL;
+}
+
+static irqreturn_t nwpserial_interrupt(int irq, void *dev_id)
+{
+ struct nwpserial_port *up = dev_id;
+ struct tty_struct *tty = up->port.info->port.tty;
+ irqreturn_t ret;
+ unsigned int iir;
+ unsigned char ch;
+
+ spin_lock(&up->port.lock);
+
+ /* check if the uart was the interrupt source. */
+ iir = dcr_read(up->dcr_host, UART_IIR);
+ if (!iir) {
+ ret = IRQ_NONE;
+ goto out;
+ }
+
+ do {
+ up->port.icount.rx++;
+ ch = dcr_read(up->dcr_host, UART_RX);
+ if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID)
+ tty_insert_flip_char(tty, ch, TTY_NORMAL);
+ } while (dcr_read(up->dcr_host, UART_RX) & UART_LSR_DR);
+
+ tty_flip_buffer_push(tty);
+ ret = IRQ_HANDLED;
+
+out:
+ spin_unlock(&up->port.lock);
+ return ret;
+}
+
+static int nwpserial_startup(struct uart_port *port)
+{
+ struct nwpserial_port *up;
+ int err;
+
+ up = container_of(port, struct nwpserial_port, port);
+
+ /* disable flow control by default */
+ up->mcr = dcr_read(up->dcr_host, UART_MCR) & ~UART_MCR_AFE;
+ dcr_write(up->dcr_host, UART_MCR, up->mcr);
+
+ /* register interrupt handler */
+ err = request_irq(up->port.irq, nwpserial_interrupt,
+ IRQF_SHARED, "nwpserial", up);
+ if (err)
+ return err;
+
+ /* enable interrupts */
+ up->ier = UART_IER_RDI;
+ dcr_write(up->dcr_host, UART_IER, up->ier);
+
+ /* enable receiving */
+ up->port.ignore_status_mask &= ~NWPSERIAL_STATUS_RXVALID;
+
+ return 0;
+}
+
+static void nwpserial_shutdown(struct uart_port *port)
+{
+ struct nwpserial_port *up;
+ up = container_of(port, struct nwpserial_port, port);
+
+ /* disable receiving */
+ up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
+
+ /* disable interrupts from this port */
+ up->ier = 0;
+ dcr_write(up->dcr_host, UART_IER, up->ier);
+
+ /* free irq */
+ free_irq(up->port.irq, port);
+}
+
+static int nwpserial_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ return -EINVAL;
+}
+
+static const char *nwpserial_type(struct uart_port *port)
+{
+ return port->type == PORT_NWPSERIAL ? "nwpserial" : NULL;
+}
+
+static void nwpserial_set_termios(struct uart_port *port,
+ struct ktermios *termios, struct ktermios *old)
+{
+ struct nwpserial_port *up;
+ up = container_of(port, struct nwpserial_port, port);
+
+ up->port.read_status_mask = NWPSERIAL_STATUS_RXVALID
+ | NWPSERIAL_STATUS_TXFULL;
+
+ up->port.ignore_status_mask = 0;
+ /* ignore all characters if CREAD is not set */
+ if ((termios->c_cflag & CREAD) == 0)
+ up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID;
+
+ /* Copy back the old hardware settings */
+ if (old)
+ tty_termios_copy_hw(termios, old);
+}
+
+static void nwpserial_break_ctl(struct uart_port *port, int ctl)
+{
+ /* N/A */
+}
+
+static void nwpserial_enable_ms(struct uart_port *port)
+{
+ /* N/A */
+}
+
+static void nwpserial_stop_rx(struct uart_port *port)
+{
+ struct nwpserial_port *up;
+ up = container_of(port, struct nwpserial_port, port);
+ /* don't forward any more data (like !CREAD) */
+ up->port.ignore_status_mask = NWPSERIAL_STATUS_RXVALID;
+}
+
+static void nwpserial_putchar(struct nwpserial_port *up, unsigned char c)
+{
+ /* check if tx buffer is full */
+ wait_for_bits(up, UART_LSR_THRE);
+ dcr_write(up->dcr_host, UART_TX, c);
+ up->port.icount.tx++;
+}
+
+static void nwpserial_start_tx(struct uart_port *port)
+{
+ struct nwpserial_port *up;
+ struct circ_buf *xmit;
+ up = container_of(port, struct nwpserial_port, port);
+ xmit = &up->port.info->xmit;
+
+ if (port->x_char) {
+ nwpserial_putchar(up, up->port.x_char);
+ port->x_char = 0;
+ }
+
+ while (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port))) {
+ nwpserial_putchar(up, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
+ }
+}
+
+static unsigned int nwpserial_get_mctrl(struct uart_port *port)
+{
+ return 0;
+}
+
+static void nwpserial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /* N/A */
+}
+
+static void nwpserial_stop_tx(struct uart_port *port)
+{
+ /* N/A */
+}
+
+static unsigned int nwpserial_tx_empty(struct uart_port *port)
+{
+ struct nwpserial_port *up;
+ unsigned long flags;
+ int ret;
+ up = container_of(port, struct nwpserial_port, port);
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ ret = dcr_read(up->dcr_host, UART_LSR);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+ return ret & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+}
+
+static struct uart_ops nwpserial_pops = {
+ .tx_empty = nwpserial_tx_empty,
+ .set_mctrl = nwpserial_set_mctrl,
+ .get_mctrl = nwpserial_get_mctrl,
+ .stop_tx = nwpserial_stop_tx,
+ .start_tx = nwpserial_start_tx,
+ .stop_rx = nwpserial_stop_rx,
+ .enable_ms = nwpserial_enable_ms,
+ .break_ctl = nwpserial_break_ctl,
+ .startup = nwpserial_startup,
+ .shutdown = nwpserial_shutdown,
+ .set_termios = nwpserial_set_termios,
+ .type = nwpserial_type,
+ .release_port = nwpserial_release_port,
+ .request_port = nwpserial_request_port,
+ .config_port = nwpserial_config_port,
+ .verify_port = nwpserial_verify_port,
+};
+
+static struct uart_driver nwpserial_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "nwpserial",
+ .dev_name = "ttySQ",
+ .major = TTY_MAJOR,
+ .minor = 68,
+ .nr = NWPSERIAL_NR,
+ .cons = NWPSERIAL_CONSOLE,
+};
+
+int nwpserial_register_port(struct uart_port *port)
+{
+ struct nwpserial_port *up = NULL;
+ int ret = -1;
+ int i;
+ static int first = 1;
+ int dcr_len;
+ int dcr_base;
+ struct device_node *dn;
+
+ mutex_lock(&nwpserial_mutex);
+
+ dn = to_of_device(port->dev)->node;
+ if (dn == NULL)
+ goto out;
+
+ /* get dcr base. */
+ dcr_base = dcr_resource_start(dn, 0);
+
+ /* find matching entry */
+ for (i = 0; i < NWPSERIAL_NR; i++)
+ if (nwpserial_ports[i].port.iobase == dcr_base) {
+ up = &nwpserial_ports[i];
+ break;
+ }
+
+ /* we didn't find a mtching entry, search for a free port */
+ if (up == NULL)
+ for (i = 0; i < NWPSERIAL_NR; i++)
+ if (nwpserial_ports[i].port.type == PORT_UNKNOWN &&
+ nwpserial_ports[i].port.iobase == 0) {
+ up = &nwpserial_ports[i];
+ break;
+ }
+
+ if (up == NULL) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (first)
+ uart_register_driver(&nwpserial_reg);
+ first = 0;
+
+ up->port.membase = port->membase;
+ up->port.irq = port->irq;
+ up->port.uartclk = port->uartclk;
+ up->port.fifosize = port->fifosize;
+ up->port.regshift = port->regshift;
+ up->port.iotype = port->iotype;
+ up->port.flags = port->flags;
+ up->port.mapbase = port->mapbase;
+ up->port.private_data = port->private_data;
+
+ if (port->dev)
+ up->port.dev = port->dev;
+
+ if (up->port.iobase != dcr_base) {
+ up->port.ops = &nwpserial_pops;
+ up->port.fifosize = 16;
+
+ spin_lock_init(&up->port.lock);
+
+ up->port.iobase = dcr_base;
+ dcr_len = dcr_resource_len(dn, 0);
+
+ up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
+ if (!DCR_MAP_OK(up->dcr_host)) {
+ printk(KERN_ERR "Cannot map DCR resources for NWPSERIAL");
+ goto out;
+ }
+ }
+
+ ret = uart_add_one_port(&nwpserial_reg, &up->port);
+ if (ret == 0)
+ ret = up->port.line;
+
+out:
+ mutex_unlock(&nwpserial_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(nwpserial_register_port);
+
+void nwpserial_unregister_port(int line)
+{
+ struct nwpserial_port *up = &nwpserial_ports[line];
+ mutex_lock(&nwpserial_mutex);
+ uart_remove_one_port(&nwpserial_reg, &up->port);
+
+ up->port.type = PORT_UNKNOWN;
+
+ mutex_unlock(&nwpserial_mutex);
+}
+EXPORT_SYMBOL(nwpserial_unregister_port);
+
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE
+static int __init nwpserial_console_init(void)
+{
+ struct nwpserial_port *up = NULL;
+ struct device_node *dn;
+ const char *name;
+ int dcr_base;
+ int dcr_len;
+ int i;
+
+ /* search for a free port */
+ for (i = 0; i < NWPSERIAL_NR; i++)
+ if (nwpserial_ports[i].port.type == PORT_UNKNOWN) {
+ up = &nwpserial_ports[i];
+ break;
+ }
+
+ if (up == NULL)
+ return -1;
+
+ name = of_get_property(of_chosen, "linux,stdout-path", NULL);
+ if (name == NULL)
+ return -1;
+
+ dn = of_find_node_by_path(name);
+ if (!dn)
+ return -1;
+
+ spin_lock_init(&up->port.lock);
+ up->port.ops = &nwpserial_pops;
+ up->port.type = PORT_NWPSERIAL;
+ up->port.fifosize = 16;
+
+ dcr_base = dcr_resource_start(dn, 0);
+ dcr_len = dcr_resource_len(dn, 0);
+ up->port.iobase = dcr_base;
+
+ up->dcr_host = dcr_map(dn, dcr_base, dcr_len);
+ if (!DCR_MAP_OK(up->dcr_host)) {
+ printk("Cannot map DCR resources for SERIAL");
+ return -1;
+ }
+ register_console(&nwpserial_console);
+ return 0;
+}
+console_initcall(nwpserial_console_init);
+#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
index 8fa0ff561e9f..14f8fa9135be 100644
--- a/drivers/serial/of_serial.c
+++ b/drivers/serial/of_serial.c
@@ -14,6 +14,7 @@
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <linux/of_platform.h>
+#include <linux/nwpserial.h>
#include <asm/prom.h>
@@ -99,9 +100,16 @@ static int __devinit of_platform_serial_probe(struct of_device *ofdev,
goto out;
switch (port_type) {
+#ifdef CONFIG_SERIAL_8250
case PORT_8250 ... PORT_MAX_8250:
ret = serial8250_register_port(&port);
break;
+#endif
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
+ case PORT_NWPSERIAL:
+ ret = nwpserial_register_port(&port);
+ break;
+#endif
default:
/* need to add code for these */
case PORT_UNKNOWN:
@@ -129,9 +137,16 @@ static int of_platform_serial_remove(struct of_device *ofdev)
{
struct of_serial_info *info = ofdev->dev.driver_data;
switch (info->type) {
+#ifdef CONFIG_SERIAL_8250
case PORT_8250 ... PORT_MAX_8250:
serial8250_unregister_port(info->line);
break;
+#endif
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
+ case PORT_NWPSERIAL:
+ nwpserial_unregister_port(info->line);
+ break;
+#endif
default:
/* need to add code for these */
break;
@@ -148,6 +163,11 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = {
{ .type = "serial", .compatible = "ns16450", .data = (void *)PORT_16450, },
{ .type = "serial", .compatible = "ns16550", .data = (void *)PORT_16550, },
{ .type = "serial", .compatible = "ns16750", .data = (void *)PORT_16750, },
+ { .type = "serial", .compatible = "ns16850", .data = (void *)PORT_16850, },
+#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
+ { .type = "serial", .compatible = "ibm,qpace-nwp-serial",
+ .data = (void *)PORT_NWPSERIAL, },
+#endif
{ .type = "serial", .data = (void *)PORT_UNKNOWN, },
{ /* end of list */ },
};
diff --git a/drivers/serial/pnx8xxx_uart.c b/drivers/serial/pnx8xxx_uart.c
index 22e30d21225e..1bb8f1b45767 100644
--- a/drivers/serial/pnx8xxx_uart.c
+++ b/drivers/serial/pnx8xxx_uart.c
@@ -187,7 +187,7 @@ static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
while (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFIFO)) {
- ch = serial_in(sport, PNX8XXX_FIFO);
+ ch = serial_in(sport, PNX8XXX_FIFO) & 0xff;
sport->port.icount.rx++;
@@ -198,9 +198,16 @@ static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
* out of the main execution path
*/
if (status & (FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE |
- PNX8XXX_UART_FIFO_RXPAR) |
+ PNX8XXX_UART_FIFO_RXPAR |
+ PNX8XXX_UART_FIFO_RXBRK) |
ISTAT_TO_SM(PNX8XXX_UART_INT_RXOVRN))) {
- if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
+ if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXBRK)) {
+ status &= ~(FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE) |
+ FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR));
+ sport->port.icount.brk++;
+ if (uart_handle_break(&sport->port))
+ goto ignore_char;
+ } else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXPAR))
sport->port.icount.parity++;
else if (status & FIFO_TO_SM(PNX8XXX_UART_FIFO_RXFE))
sport->port.icount.frame++;
@@ -284,14 +291,8 @@ static irqreturn_t pnx8xxx_int(int irq, void *dev_id)
/* Get the interrupts */
status = serial_in(sport, PNX8XXX_ISTAT) & serial_in(sport, PNX8XXX_IEN);
- /* Break signal received */
- if (status & PNX8XXX_UART_INT_BREAK) {
- sport->port.icount.brk++;
- uart_handle_break(&sport->port);
- }
-
- /* Byte received */
- if (status & PNX8XXX_UART_INT_RX)
+ /* Byte or break signal received */
+ if (status & (PNX8XXX_UART_INT_RX | PNX8XXX_UART_INT_BREAK))
pnx8xxx_rx_chars(sport);
/* TX holding register empty - transmit a byte */
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 5e39bac9c51b..56ff3e6864ea 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -670,8 +670,7 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
dev_dbg(controller, "new message %p submitted for %s\n",
msg, spi->dev.bus_id);
- if (unlikely(list_empty(&msg->transfers)
- || !spi->max_speed_hz))
+ if (unlikely(list_empty(&msg->transfers)))
return -EINVAL;
if (as->stopping)
diff --git a/drivers/spi/spi_lm70llp.c b/drivers/spi/spi_lm70llp.c
index af6526767e2a..568c781ad91c 100644
--- a/drivers/spi/spi_lm70llp.c
+++ b/drivers/spi/spi_lm70llp.c
@@ -1,5 +1,5 @@
/*
- * spi_lm70llp.c - driver for lm70llp eval board for the LM70 sensor
+ * spi_lm70llp.c - driver for LM70EVAL-LLP board for the LM70 sensor
*
* Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com>
*
@@ -40,8 +40,12 @@
* master controller driver. The hwmon/lm70 driver is a "SPI protocol
* driver", layered on top of this one and usable without the lm70llp.
*
+ * Datasheet and Schematic:
* The LM70 is a temperature sensor chip from National Semiconductor; its
* datasheet is available at http://www.national.com/pf/LM/LM70.html
+ * The schematic for this particular board (the LM70EVAL-LLP) is
+ * available (on page 4) here:
+ * http://www.national.com/appinfo/tempsensors/files/LM70LLPEVALmanual.pdf
*
* Also see Documentation/spi/spi-lm70llp. The SPI<->parport code here is
* (heavily) based on spi-butterfly by David Brownell.
@@ -64,7 +68,7 @@
*
* Note that parport pin 13 actually gets inverted by the transistor
* arrangement which lets either the parport or the LM70 drive the
- * SI/SO signal.
+ * SI/SO signal (see the schematic for details).
*/
#define DRVNAME "spi-lm70llp"
@@ -106,12 +110,16 @@ static inline struct spi_lm70llp *spidev_to_pp(struct spi_device *spi)
static inline void deassertCS(struct spi_lm70llp *pp)
{
u8 data = parport_read_data(pp->port);
+
+ data &= ~0x80; /* pull D7/SI-out low while de-asserted */
parport_write_data(pp->port, data | nCS);
}
static inline void assertCS(struct spi_lm70llp *pp)
{
u8 data = parport_read_data(pp->port);
+
+ data |= 0x80; /* pull D7/SI-out high so lm70 drives SO-in */
parport_write_data(pp->port, data & ~nCS);
}
@@ -184,22 +192,7 @@ static void lm70_chipselect(struct spi_device *spi, int value)
*/
static u32 lm70_txrx(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
{
- static u32 sio=0;
- static int first_time=1;
-
- /* First time: perform SPI bitbang and return the LSB of
- * the result of the SPI call.
- */
- if (first_time) {
- sio = bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
- first_time=0;
- return (sio & 0x00ff);
- }
- /* Return the MSB of the result of the SPI call */
- else {
- first_time=1;
- return (sio >> 8);
- }
+ return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
}
static void spi_lm70llp_attach(struct parport *p)
@@ -293,10 +286,9 @@ static void spi_lm70llp_attach(struct parport *p)
status = -ENODEV;
goto out_bitbang_stop;
}
- pp->spidev_lm70->bits_per_word = 16;
+ pp->spidev_lm70->bits_per_word = 8;
lm70llp = pp;
-
return;
out_bitbang_stop:
@@ -326,7 +318,6 @@ static void spi_lm70llp_detach(struct parport *p)
/* power down */
parport_write_data(pp->port, 0);
- msleep(10);
parport_release(pp->pd);
parport_unregister_device(pp->pd);
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index 68d6f4988fb5..fe7e5f35e5d0 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -15,12 +15,15 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
+
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/of_spi.h>
+
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/io.h>
-#include <syslib/virtex_devices.h>
-
#define XILINX_SPI_NAME "xilinx_spi"
/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
@@ -144,23 +147,14 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
u8 bits_per_word;
- u32 hz;
- struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
- hz = (t) ? t->speed_hz : spi->max_speed_hz;
if (bits_per_word != 8) {
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
__func__, bits_per_word);
return -EINVAL;
}
- if (hz && xspi->speed_hz > hz) {
- dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n",
- __func__, hz);
- return -EINVAL;
- }
-
return 0;
}
@@ -304,32 +298,38 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int __init xilinx_spi_probe(struct platform_device *dev)
+static int __init xilinx_spi_of_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
{
- int ret = 0;
struct spi_master *master;
struct xilinx_spi *xspi;
- struct xspi_platform_data *pdata;
- struct resource *r;
+ struct resource r_irq_struct;
+ struct resource r_mem_struct;
+
+ struct resource *r_irq = &r_irq_struct;
+ struct resource *r_mem = &r_mem_struct;
+ int rc = 0;
+ const u32 *prop;
+ int len;
/* Get resources(memory, IRQ) associated with the device */
- master = spi_alloc_master(&dev->dev, sizeof(struct xilinx_spi));
+ master = spi_alloc_master(&ofdev->dev, sizeof(struct xilinx_spi));
if (master == NULL) {
return -ENOMEM;
}
- platform_set_drvdata(dev, master);
- pdata = dev->dev.platform_data;
+ dev_set_drvdata(&ofdev->dev, master);
- if (pdata == NULL) {
- ret = -ENODEV;
+ rc = of_address_to_resource(ofdev->node, 0, r_mem);
+ if (rc) {
+ dev_warn(&ofdev->dev, "invalid address\n");
goto put_master;
}
- r = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- ret = -ENODEV;
+ rc = of_irq_to_resource(ofdev->node, 0, r_irq);
+ if (rc == NO_IRQ) {
+ dev_warn(&ofdev->dev, "no IRQ found\n");
goto put_master;
}
@@ -341,47 +341,57 @@ static int __init xilinx_spi_probe(struct platform_device *dev)
xspi->bitbang.master->setup = xilinx_spi_setup;
init_completion(&xspi->done);
- if (!request_mem_region(r->start,
- r->end - r->start + 1, XILINX_SPI_NAME)) {
- ret = -ENXIO;
+ xspi->irq = r_irq->start;
+
+ if (!request_mem_region(r_mem->start,
+ r_mem->end - r_mem->start + 1, XILINX_SPI_NAME)) {
+ rc = -ENXIO;
+ dev_warn(&ofdev->dev, "memory request failure\n");
goto put_master;
}
- xspi->regs = ioremap(r->start, r->end - r->start + 1);
+ xspi->regs = ioremap(r_mem->start, r_mem->end - r_mem->start + 1);
if (xspi->regs == NULL) {
- ret = -ENOMEM;
+ rc = -ENOMEM;
+ dev_warn(&ofdev->dev, "ioremap failure\n");
goto put_master;
}
+ xspi->irq = r_irq->start;
- ret = platform_get_irq(dev, 0);
- if (ret < 0) {
- ret = -ENXIO;
- goto unmap_io;
- }
- xspi->irq = ret;
+ /* dynamic bus assignment */
+ master->bus_num = -1;
- master->bus_num = pdata->bus_num;
- master->num_chipselect = pdata->num_chipselect;
- xspi->speed_hz = pdata->speed_hz;
+ /* number of slave select bits is required */
+ prop = of_get_property(ofdev->node, "xlnx,num-ss-bits", &len);
+ if (!prop || len < sizeof(*prop)) {
+ dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
+ goto put_master;
+ }
+ master->num_chipselect = *prop;
/* SPI controller initializations */
xspi_init_hw(xspi->regs);
/* Register for SPI Interrupt */
- ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
- if (ret != 0)
+ rc = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
+ if (rc != 0) {
+ dev_warn(&ofdev->dev, "irq request failure: %d\n", xspi->irq);
goto unmap_io;
+ }
- ret = spi_bitbang_start(&xspi->bitbang);
- if (ret != 0) {
- dev_err(&dev->dev, "spi_bitbang_start FAILED\n");
+ rc = spi_bitbang_start(&xspi->bitbang);
+ if (rc != 0) {
+ dev_err(&ofdev->dev, "spi_bitbang_start FAILED\n");
goto free_irq;
}
- dev_info(&dev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n",
- r->start, (u32)xspi->regs, xspi->irq);
+ dev_info(&ofdev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n",
+ (unsigned int)r_mem->start, (u32)xspi->regs, xspi->irq);
- return ret;
+ /* Add any subnodes on the SPI bus */
+ of_register_spi_devices(master, ofdev->node);
+
+ return rc;
free_irq:
free_irq(xspi->irq, xspi);
@@ -389,21 +399,21 @@ unmap_io:
iounmap(xspi->regs);
put_master:
spi_master_put(master);
- return ret;
+ return rc;
}
-static int __devexit xilinx_spi_remove(struct platform_device *dev)
+static int __devexit xilinx_spi_remove(struct of_device *ofdev)
{
struct xilinx_spi *xspi;
struct spi_master *master;
- master = platform_get_drvdata(dev);
+ master = platform_get_drvdata(ofdev);
xspi = spi_master_get_devdata(master);
spi_bitbang_stop(&xspi->bitbang);
free_irq(xspi->irq, xspi);
iounmap(xspi->regs);
- platform_set_drvdata(dev, 0);
+ dev_set_drvdata(&ofdev->dev, 0);
spi_master_put(xspi->bitbang.master);
return 0;
@@ -412,27 +422,42 @@ static int __devexit xilinx_spi_remove(struct platform_device *dev)
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:" XILINX_SPI_NAME);
-static struct platform_driver xilinx_spi_driver = {
- .probe = xilinx_spi_probe,
- .remove = __devexit_p(xilinx_spi_remove),
+static int __exit xilinx_spi_of_remove(struct of_device *op)
+{
+ return xilinx_spi_remove(op);
+}
+
+static struct of_device_id xilinx_spi_of_match[] = {
+ { .compatible = "xlnx,xps-spi-2.00.a", },
+ { .compatible = "xlnx,xps-spi-2.00.b", },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
+
+static struct of_platform_driver xilinx_spi_of_driver = {
+ .owner = THIS_MODULE,
+ .name = "xilinx-xps-spi",
+ .match_table = xilinx_spi_of_match,
+ .probe = xilinx_spi_of_probe,
+ .remove = __exit_p(xilinx_spi_of_remove),
.driver = {
- .name = XILINX_SPI_NAME,
+ .name = "xilinx-xps-spi",
.owner = THIS_MODULE,
},
};
static int __init xilinx_spi_init(void)
{
- return platform_driver_register(&xilinx_spi_driver);
+ return of_register_platform_driver(&xilinx_spi_of_driver);
}
module_init(xilinx_spi_init);
static void __exit xilinx_spi_exit(void)
{
- platform_driver_unregister(&xilinx_spi_driver);
+ of_unregister_platform_driver(&xilinx_spi_of_driver);
}
module_exit(xilinx_spi_exit);
-
MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
MODULE_DESCRIPTION("Xilinx SPI driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index 06372b227bb2..36a93b95e3f2 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -557,7 +557,7 @@ unsigned int comedi_buf_munge(comedi_async * async, unsigned int num_bytes)
block_size = num_bytes - count;
if (block_size < 0) {
rt_printk("%s: %s: bug! block_size is negative\n",
- __FILE__, __FUNCTION__);
+ __FILE__, __func__);
break;
}
if ((int)(async->munge_ptr + block_size -
diff --git a/drivers/staging/epl/Edrv8139.c b/drivers/staging/epl/Edrv8139.c
index 88ab4a4f1023..296354aaa9c7 100644
--- a/drivers/staging/epl/Edrv8139.c
+++ b/drivers/staging/epl/Edrv8139.c
@@ -391,19 +391,19 @@ tEplKernel EdrvInit(tEdrvInitParam * pEdrvInitParam_p)
// register PCI driver
iResult = pci_register_driver(&EdrvDriver);
if (iResult != 0) {
- printk("%s pci_register_driver failed with %d\n", __FUNCTION__,
+ printk("%s pci_register_driver failed with %d\n", __func__,
iResult);
Ret = kEplNoResource;
goto Exit;
}
if (EdrvInstance_l.m_pPciDev == NULL) {
- printk("%s m_pPciDev=NULL\n", __FUNCTION__);
+ printk("%s m_pPciDev=NULL\n", __func__);
Ret = kEplNoResource;
goto Exit;
}
// read MAC address from controller
- printk("%s local MAC = ", __FUNCTION__);
+ printk("%s local MAC = ", __func__);
for (iResult = 0; iResult < 6; iResult++) {
pEdrvInitParam_p->m_abMyMacAddr[iResult] =
EDRV_REGB_READ((EDRV_REGDW_IDR0 + iResult));
@@ -434,7 +434,7 @@ tEplKernel EdrvShutdown(void)
{
// unregister PCI driver
- printk("%s calling pci_unregister_driver()\n", __FUNCTION__);
+ printk("%s calling pci_unregister_driver()\n", __func__);
pci_unregister_driver(&EdrvDriver);
return kEplSuccessful;
@@ -621,7 +621,7 @@ tEplKernel EdrvSendTxMsg(tEdrvTxBuffer * pBuffer_p)
EDRV_REGDW_READ((EDRV_REGDW_TSD0 +
(EdrvInstance_l.m_uiCurTxDesc *
sizeof(DWORD))));
- printk("%s InvOp TSD%u = 0x%08lX", __FUNCTION__,
+ printk("%s InvOp TSD%u = 0x%08lX", __func__,
EdrvInstance_l.m_uiCurTxDesc, dwTemp);
printk(" Cmd = 0x%02X\n",
(WORD) EDRV_REGB_READ(EDRV_REGB_COMMAND));
@@ -646,7 +646,7 @@ tEplKernel EdrvSendTxMsg(tEdrvTxBuffer * pBuffer_p)
dwTemp =
EDRV_REGDW_READ((EDRV_REGDW_TSAD0 +
(EdrvInstance_l.m_uiCurTxDesc * sizeof(DWORD))));
-// printk("%s TSAD%u = 0x%08lX", __FUNCTION__, EdrvInstance_l.m_uiCurTxDesc, dwTemp);
+// printk("%s TSAD%u = 0x%08lX", __func__, EdrvInstance_l.m_uiCurTxDesc, dwTemp);
// start transmission
EDRV_REGDW_WRITE((EDRV_REGDW_TSD0 +
@@ -786,7 +786,7 @@ static int TgtEthIsr(int nIrqNum_p, void *ppDevInstData_p,
if (EdrvInstance_l.m_pbTxBuf == NULL) {
printk("%s Tx buffers currently not allocated\n",
- __FUNCTION__);
+ __func__);
goto Exit;
}
// read transmit status
@@ -842,7 +842,7 @@ static int TgtEthIsr(int nIrqNum_p, void *ppDevInstData_p,
if (EdrvInstance_l.m_pbRxBuf == NULL) {
printk("%s Rx buffers currently not allocated\n",
- __FUNCTION__);
+ __func__);
goto Exit;
}
// read current offset in receive buffer
@@ -944,7 +944,7 @@ static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
DWORD dwTemp;
if (EdrvInstance_l.m_pPciDev != NULL) { // Edrv is already connected to a PCI device
- printk("%s device %s discarded\n", __FUNCTION__,
+ printk("%s device %s discarded\n", __func__,
pci_name(pPciDev));
iResult = -ENODEV;
goto Exit;
@@ -953,7 +953,7 @@ static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
if (pPciDev->revision >= 0x20) {
printk
("%s device %s is an enhanced 8139C+ version, which is not supported\n",
- __FUNCTION__, pci_name(pPciDev));
+ __func__, pci_name(pPciDev));
iResult = -ENODEV;
goto Exit;
}
@@ -961,7 +961,7 @@ static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
EdrvInstance_l.m_pPciDev = pPciDev;
// enable device
- printk("%s enable device\n", __FUNCTION__);
+ printk("%s enable device\n", __func__);
iResult = pci_enable_device(pPciDev);
if (iResult != 0) {
goto Exit;
@@ -972,13 +972,13 @@ static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
goto Exit;
}
- printk("%s request regions\n", __FUNCTION__);
+ printk("%s request regions\n", __func__);
iResult = pci_request_regions(pPciDev, DRV_NAME);
if (iResult != 0) {
goto Exit;
}
- printk("%s ioremap\n", __FUNCTION__);
+ printk("%s ioremap\n", __func__);
EdrvInstance_l.m_pIoAddr =
ioremap(pci_resource_start(pPciDev, 1),
pci_resource_len(pPciDev, 1));
@@ -987,11 +987,11 @@ static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
goto Exit;
}
// enable PCI busmaster
- printk("%s enable busmaster\n", __FUNCTION__);
+ printk("%s enable busmaster\n", __func__);
pci_set_master(pPciDev);
// reset controller
- printk("%s reset controller\n", __FUNCTION__);
+ printk("%s reset controller\n", __func__);
EDRV_REGB_WRITE(EDRV_REGB_COMMAND, EDRV_REGB_COMMAND_RST);
// wait until reset has finished
@@ -1008,20 +1008,20 @@ static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
dwTemp = EDRV_REGDW_READ(EDRV_REGDW_TCR);
if (((dwTemp & EDRV_REGDW_TCR_VER_MASK) != EDRV_REGDW_TCR_VER_C)
&& ((dwTemp & EDRV_REGDW_TCR_VER_MASK) != EDRV_REGDW_TCR_VER_D)) { // unsupported chip
- printk("%s Unsupported chip! TCR = 0x%08lX\n", __FUNCTION__,
+ printk("%s Unsupported chip! TCR = 0x%08lX\n", __func__,
dwTemp);
iResult = -ENODEV;
goto Exit;
}
// disable interrupts
- printk("%s disable interrupts\n", __FUNCTION__);
+ printk("%s disable interrupts\n", __func__);
EDRV_REGW_WRITE(EDRV_REGW_INT_MASK, 0);
// acknowledge all pending interrupts
EDRV_REGW_WRITE(EDRV_REGW_INT_STATUS,
EDRV_REGW_READ(EDRV_REGW_INT_STATUS));
// install interrupt handler
- printk("%s install interrupt handler\n", __FUNCTION__);
+ printk("%s install interrupt handler\n", __func__);
iResult =
request_irq(pPciDev->irq, TgtEthIsr, IRQF_SHARED,
DRV_NAME /*pPciDev->dev.name */ , pPciDev);
@@ -1031,16 +1031,16 @@ static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
/*
// unlock configuration registers
- printk("%s unlock configuration registers\n", __FUNCTION__);
+ printk("%s unlock configuration registers\n", __func__);
EDRV_REGB_WRITE(EDRV_REGB_CMD9346, EDRV_REGB_CMD9346_UNLOCK);
// check if user specified a MAC address
- printk("%s check specified MAC address\n", __FUNCTION__);
+ printk("%s check specified MAC address\n", __func__);
for (iResult = 0; iResult < 6; iResult++)
{
if (EdrvInstance_l.m_InitParam.m_abMyMacAddr[iResult] != 0)
{
- printk("%s set local MAC address\n", __FUNCTION__);
+ printk("%s set local MAC address\n", __func__);
// write this MAC address to controller
EDRV_REGDW_WRITE(EDRV_REGDW_IDR0,
le32_to_cpu(*((DWORD*)&EdrvInstance_l.m_InitParam.m_abMyMacAddr[0])));
@@ -1059,7 +1059,7 @@ static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
*/
// allocate buffers
- printk("%s allocate buffers\n", __FUNCTION__);
+ printk("%s allocate buffers\n", __func__);
EdrvInstance_l.m_pbTxBuf =
pci_alloc_consistent(pPciDev, EDRV_TX_BUFFER_SIZE,
&EdrvInstance_l.m_pTxBufDma);
@@ -1076,7 +1076,7 @@ static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
goto Exit;
}
// reset pointers for Tx buffers
- printk("%s reset pointers fo Tx buffers\n", __FUNCTION__);
+ printk("%s reset pointers fo Tx buffers\n", __func__);
EDRV_REGDW_WRITE(EDRV_REGDW_TSAD0, 0);
dwTemp = EDRV_REGDW_READ(EDRV_REGDW_TSAD0);
EDRV_REGDW_WRITE(EDRV_REGDW_TSAD1, 0);
@@ -1090,11 +1090,11 @@ static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
(WORD) EDRV_REGB_READ(EDRV_REGB_COMMAND));
// set pointer for receive buffer in controller
- printk("%s set pointer to Rx buffer\n", __FUNCTION__);
+ printk("%s set pointer to Rx buffer\n", __func__);
EDRV_REGDW_WRITE(EDRV_REGDW_RBSTART, EdrvInstance_l.m_pRxBufDma);
// enable transmitter and receiver
- printk("%s enable Tx and Rx", __FUNCTION__);
+ printk("%s enable Tx and Rx", __func__);
EDRV_REGB_WRITE(EDRV_REGB_COMMAND,
(EDRV_REGB_COMMAND_RE | EDRV_REGB_COMMAND_TE));
printk(" Command = 0x%02X\n",
@@ -1104,12 +1104,12 @@ static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
EDRV_REGDW_WRITE(EDRV_REGDW_MPC, 0);
// set transmit configuration register
- printk("%s set Tx conf register", __FUNCTION__);
+ printk("%s set Tx conf register", __func__);
EDRV_REGDW_WRITE(EDRV_REGDW_TCR, EDRV_REGDW_TCR_DEF);
printk(" = 0x%08X\n", EDRV_REGDW_READ(EDRV_REGDW_TCR));
// set receive configuration register
- printk("%s set Rx conf register", __FUNCTION__);
+ printk("%s set Rx conf register", __func__);
EDRV_REGDW_WRITE(EDRV_REGDW_RCR, EDRV_REGDW_RCR_DEF);
printk(" = 0x%08X\n", EDRV_REGDW_READ(EDRV_REGDW_RCR));
@@ -1121,7 +1121,7 @@ static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
/*
// enable transmitter and receiver
- printk("%s enable Tx and Rx", __FUNCTION__);
+ printk("%s enable Tx and Rx", __func__);
EDRV_REGB_WRITE(EDRV_REGB_COMMAND, (EDRV_REGB_COMMAND_RE | EDRV_REGB_COMMAND_TE));
printk(" Command = 0x%02X\n", (WORD) EDRV_REGB_READ(EDRV_REGB_COMMAND));
*/
@@ -1129,11 +1129,11 @@ static int EdrvInitOne(struct pci_dev *pPciDev, const struct pci_device_id *pId)
EDRV_REGW_WRITE(EDRV_REGW_MULINT, 0);
// enable interrupts
- printk("%s enable interrupts\n", __FUNCTION__);
+ printk("%s enable interrupts\n", __func__);
EDRV_REGW_WRITE(EDRV_REGW_INT_MASK, EDRV_REGW_INT_MASK_DEF);
Exit:
- printk("%s finished with %d\n", __FUNCTION__, iResult);
+ printk("%s finished with %d\n", __func__, iResult);
return iResult;
}
diff --git a/drivers/staging/epl/EplSdoAsySequ.c b/drivers/staging/epl/EplSdoAsySequ.c
index 991c6be880c0..6b6a9975d78b 100644
--- a/drivers/staging/epl/EplSdoAsySequ.c
+++ b/drivers/staging/epl/EplSdoAsySequ.c
@@ -876,7 +876,7 @@ static tEplKernel EplSdoAsySeqProcess(unsigned int uiHandle_p,
{
/*
PRINTF3("%s scon=%u rcon=%u\n",
- __FUNCTION__,
+ __func__,
pRecFrame_p->m_le_bSendSeqNumCon,
pRecFrame_p->m_le_bRecSeqNumCon);
*/
diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c
index 61d7c5df87af..6136e3f8762d 100644
--- a/drivers/staging/frontier/alphatrack.c
+++ b/drivers/staging/frontier/alphatrack.c
@@ -239,7 +239,7 @@ static void usb_alphatrack_interrupt_in_callback(struct urb *urb)
goto exit;
} else {
dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
- __FUNCTION__, urb->status);
+ __func__, urb->status);
goto resubmit; /* maybe we can recover */
}
}
@@ -261,7 +261,7 @@ static void usb_alphatrack_interrupt_in_callback(struct urb *urb)
if(dev->offline > 0 && dev->interrupt_in_buffer[1] != 0xff) { dev->offline = 0; }
if(dev->offline == 0 && dev->interrupt_in_buffer[1] == 0xff) { dev->offline = 1; }
#endif
- dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
+ dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __func__,dev->ring_head,dev->ring_tail);
next_ring_head = (dev->ring_head+1) % ring_buffer_size;
if (next_ring_head != dev->ring_tail) {
@@ -305,7 +305,7 @@ static void usb_alphatrack_interrupt_out_callback(struct urb *urb)
urb->status == -ESHUTDOWN))
dbg_info(&dev->intf->dev,
"%s - nonzero write interrupt status received: %d\n",
- __FUNCTION__, urb->status);
+ __func__, urb->status);
atomic_dec(&dev->writes_pending);
dev->interrupt_out_busy = 0;
wake_up_interruptible(&dev->write_wait);
@@ -330,7 +330,7 @@ static int usb_alphatrack_open(struct inode *inode, struct file *file)
if (!interface) {
err("%s - error, can't find device for minor %d\n",
- __FUNCTION__, subminor);
+ __func__, subminor);
retval = -ENODEV;
goto unlock_disconnect_exit;
}
@@ -514,7 +514,7 @@ static ssize_t usb_alphatrack_read(struct file *file, char __user *buffer, size_
}
dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
c+=INPUT_CMD_SIZE;
- dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
+ dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __func__,dev->ring_head,dev->ring_tail);
}
retval = c;
@@ -573,7 +573,7 @@ static ssize_t usb_alphatrack_write(struct file *file, const char __user *buffer
if (bytes_to_write < count)
dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write);
- dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __FUNCTION__, count, bytes_to_write);
+ dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __func__, count, bytes_to_write);
if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
retval = -EFAULT;
diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c
index 275faa762388..79abb6b16f74 100644
--- a/drivers/staging/frontier/tranzport.c
+++ b/drivers/staging/frontier/tranzport.c
@@ -335,7 +335,7 @@ static void usb_tranzport_interrupt_in_callback(struct urb *urb)
goto exit;
} else {
dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
- __FUNCTION__, urb->status);
+ __func__, urb->status);
goto resubmit; /* maybe we can recover */
}
}
@@ -345,7 +345,7 @@ static void usb_tranzport_interrupt_in_callback(struct urb *urb)
"Urb length was %d bytes!! Do something intelligent \n", urb->actual_length);
} else {
dbg_info(&dev->intf->dev, "%s: received: %02x%02x%02x%02x%02x%02x%02x%02x\n",
- __FUNCTION__, dev->interrupt_in_buffer[0],dev->interrupt_in_buffer[1],dev->interrupt_in_buffer[2],dev->interrupt_in_buffer[3],dev->interrupt_in_buffer[4],dev->interrupt_in_buffer[5],dev->interrupt_in_buffer[6],dev->interrupt_in_buffer[7]);
+ __func__, dev->interrupt_in_buffer[0],dev->interrupt_in_buffer[1],dev->interrupt_in_buffer[2],dev->interrupt_in_buffer[3],dev->interrupt_in_buffer[4],dev->interrupt_in_buffer[5],dev->interrupt_in_buffer[6],dev->interrupt_in_buffer[7]);
#if SUPPRESS_EXTRA_OFFLINE_EVENTS
if(dev->offline == 2 && dev->interrupt_in_buffer[1] == 0xff) { goto resubmit; }
if(dev->offline == 1 && dev->interrupt_in_buffer[1] == 0xff) { dev->offline = 2; goto resubmit; }
@@ -355,7 +355,7 @@ static void usb_tranzport_interrupt_in_callback(struct urb *urb)
if(dev->offline == 0 && dev->interrupt_in_buffer[1] == 0xff) { dev->offline = 1; }
#endif
- dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
+ dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __func__,dev->ring_head,dev->ring_tail);
next_ring_head = (dev->ring_head+1) % ring_buffer_size;
@@ -399,7 +399,7 @@ static void usb_tranzport_interrupt_out_callback(struct urb *urb)
urb->status == -ESHUTDOWN))
dbg_info(&dev->intf->dev,
"%s - nonzero write interrupt status received: %d\n",
- __FUNCTION__, urb->status);
+ __func__, urb->status);
dev->interrupt_out_busy = 0;
wake_up_interruptible(&dev->write_wait);
@@ -424,7 +424,7 @@ static int usb_tranzport_open(struct inode *inode, struct file *file)
if (!interface) {
err("%s - error, can't find device for minor %d\n",
- __FUNCTION__, subminor);
+ __func__, subminor);
retval = -ENODEV;
goto unlock_disconnect_exit;
}
@@ -613,7 +613,7 @@ static ssize_t usb_tranzport_read(struct file *file, char __user *buffer, size_t
}
dbg_info(&dev->intf->dev, "%s: copying to userspace: %02x%02x%02x%02x%02x%02x%02x%02x\n",
- __FUNCTION__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
+ __func__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
#if BUFFERED_READS
c = 0;
@@ -632,7 +632,7 @@ static ssize_t usb_tranzport_read(struct file *file, char __user *buffer, size_t
// FIXME the math is wrong for going in reverse, actually, as the midi spec doesn't allow signed chars
dbg_info(&dev->intf->dev, "%s: trying to compress: %02x%02x%02x%02x%02x %02x %02x %02x\n",
- __FUNCTION__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
+ __func__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
if(((*dev->ring_buffer)[dev->ring_tail].cmd[6] != 0 &&
@@ -645,7 +645,7 @@ static ssize_t usb_tranzport_read(struct file *file, char __user *buffer, size_t
((*dev->ring_buffer)[dev->ring_tail].cmd[5] == (*dev->ring_buffer)[next_tail].cmd[5]))
{
dbg_info(&dev->intf->dev, "%s: should compress: %02x%02x%02x%02x%02x%02x%02x%02x\n",
- __FUNCTION__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
+ __func__, (*dev->ring_buffer)[dev->ring_tail].cmd[0],(*dev->ring_buffer)[dev->ring_tail].cmd[1],(*dev->ring_buffer)[dev->ring_tail].cmd[2],(*dev->ring_buffer)[dev->ring_tail].cmd[3],(*dev->ring_buffer)[dev->ring_tail].cmd[4],(*dev->ring_buffer)[dev->ring_tail].cmd[5],(*dev->ring_buffer)[dev->ring_tail].cmd[6],(*dev->ring_buffer)[dev->ring_tail].cmd[7]);
newwheel += oldwheel;
if(oldwheel > 0 && !(newwheel > 0)) {
@@ -673,7 +673,7 @@ static ssize_t usb_tranzport_read(struct file *file, char __user *buffer, size_t
dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
c+=8;
- dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
+ dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __func__,dev->ring_head,dev->ring_tail);
}
retval = c;
@@ -684,7 +684,7 @@ static ssize_t usb_tranzport_read(struct file *file, char __user *buffer, size_t
}
dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
- dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __FUNCTION__,dev->ring_head,dev->ring_tail);
+ dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", __func__,dev->ring_head,dev->ring_tail);
retval = 8;
#endif /* BUFFERED_READS */
@@ -743,7 +743,7 @@ static ssize_t usb_tranzport_write(struct file *file, const char __user *buffer,
if (bytes_to_write < count)
dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write);
- dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __FUNCTION__, count, bytes_to_write);
+ dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __func__, count, bytes_to_write);
if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
retval = -EFAULT;
diff --git a/drivers/staging/go7007/go7007-v4l2.c b/drivers/staging/go7007/go7007-v4l2.c
index 4f7237a03ad1..868edb65e7bf 100644
--- a/drivers/staging/go7007/go7007-v4l2.c
+++ b/drivers/staging/go7007/go7007-v4l2.c
@@ -1712,8 +1712,7 @@ static int go7007_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
page = alloc_page(GFP_USER | __GFP_DMA32);
if (!page)
return VM_FAULT_OOM;
- clear_user_page(page_address(page), (unsigned long)vmf->virtual_address,
- page);
+ clear_user_highpage(page, (unsigned long)vmf->virtual_address);
vmf->page = page;
return 0;
}
diff --git a/drivers/staging/meilhaus/me0600_ext_irq.c b/drivers/staging/meilhaus/me0600_ext_irq.c
index a449ab200940..eba18adecb72 100644
--- a/drivers/staging/meilhaus/me0600_ext_irq.c
+++ b/drivers/staging/meilhaus/me0600_ext_irq.c
@@ -360,7 +360,7 @@ static irqreturn_t me0600_isr(int irq, void *dev_id, struct pt_regs *regs)
if (instance->lintno > 1) {
PERROR_CRITICAL
("%s():Wrong subdevice index=%d plx:irq_status_reg=0x%04X.\n",
- __FUNCTION__, instance->lintno, inl(instance->intcsr));
+ __func__, instance->lintno, inl(instance->intcsr));
return IRQ_NONE;
}
@@ -384,7 +384,7 @@ static irqreturn_t me0600_isr(int irq, void *dev_id, struct pt_regs *regs)
} else {
PINFO
("%ld Shared interrupt. %s(): idx=0 plx:irq_status_reg=0x%04X\n",
- jiffies, __FUNCTION__, status);
+ jiffies, __func__, status);
ret = IRQ_NONE;
}
spin_unlock(instance->intcsr_lock);
diff --git a/drivers/staging/meilhaus/me1400_ext_irq.c b/drivers/staging/meilhaus/me1400_ext_irq.c
index b8c2696bc150..b4df7cc58ab7 100644
--- a/drivers/staging/meilhaus/me1400_ext_irq.c
+++ b/drivers/staging/meilhaus/me1400_ext_irq.c
@@ -349,7 +349,7 @@ static irqreturn_t me1400_ext_irq_isr(int irq, void *dev_id,
(PLX_LOCAL_INT1_STATE | PLX_LOCAL_INT1_EN | PLX_PCI_INT_EN)) {
spin_unlock(&instance->subdevice_lock);
PINFO("%ld Shared interrupt. %s(): irq_status_reg=0x%04X\n",
- jiffies, __FUNCTION__, status);
+ jiffies, __func__, status);
return IRQ_NONE;
}
diff --git a/drivers/staging/meilhaus/me1600_ao.c b/drivers/staging/meilhaus/me1600_ao.c
index 6f26665b30b7..d127c6b00307 100644
--- a/drivers/staging/meilhaus/me1600_ao.c
+++ b/drivers/staging/meilhaus/me1600_ao.c
@@ -977,7 +977,7 @@ static void me1600_ao_work_control_task(struct work_struct *work)
container_of((void *)work, me1600_ao_subdevice_t, ao_control_task);
#endif
- PINFO("<%s: %ld> executed. idx=%d\n", __FUNCTION__, jiffies,
+ PINFO("<%s: %ld> executed. idx=%d\n", __func__, jiffies,
instance->ao_idx);
if (!((instance->ao_regs_shadows)->trigger & instance->ao_idx)) { // Output was triggerd.
@@ -1027,7 +1027,7 @@ static void me1600_ao_work_control_task(struct work_struct *work)
queue_delayed_work(instance->me1600_workqueue,
&instance->ao_control_task, 1);
} else {
- PINFO("<%s> Ending control task.\n", __FUNCTION__);
+ PINFO("<%s> Ending control task.\n", __func__);
}
}
diff --git a/drivers/staging/meilhaus/me4600_ai.c b/drivers/staging/meilhaus/me4600_ai.c
index 1a0de5dea277..0a8c9d737e90 100644
--- a/drivers/staging/meilhaus/me4600_ai.c
+++ b/drivers/staging/meilhaus/me4600_ai.c
@@ -2629,11 +2629,11 @@ static irqreturn_t me4600_ai_isr(int irq, void *dev_id, struct pt_regs *regs)
if ((irq_status & (ME4600_IRQ_STATUS_BIT_AI_HF | ME4600_IRQ_STATUS_BIT_SC | ME4600_IRQ_STATUS_BIT_LE)) == ME4600_IRQ_STATUS_BIT_LE) { //This is security check case. LE is unused. This should never ever happend.
PINFO
("%ld Shared interrupt. %s(): irq_status_reg=LE_IRQ\n",
- jiffies, __FUNCTION__);
+ jiffies, __func__);
} else {
PINFO
("%ld Shared interrupt. %s(): irq_status_reg=0x%04X\n",
- jiffies, __FUNCTION__, irq_status);
+ jiffies, __func__, irq_status);
}
#endif
return IRQ_NONE;
@@ -3329,7 +3329,7 @@ static void me4600_ai_work_control_task(struct work_struct *work)
instance =
container_of((void *)work, me4600_ai_subdevice_t, ai_control_task);
#endif
- PINFO("<%s: %ld> executed.\n", __FUNCTION__, jiffies);
+ PINFO("<%s: %ld> executed.\n", __func__, jiffies);
status = inl(instance->status_reg);
PDEBUG_REG("status_reg inl(0x%lX+0x%lX)=0x%x\n", instance->reg_base,
@@ -3428,7 +3428,7 @@ static void me4600_ai_work_control_task(struct work_struct *work)
queue_delayed_work(instance->me4600_workqueue,
&instance->ai_control_task, 1);
} else {
- PINFO("<%s> Ending control task.\n", __FUNCTION__);
+ PINFO("<%s> Ending control task.\n", __func__);
}
}
diff --git a/drivers/staging/meilhaus/me4600_ao.c b/drivers/staging/meilhaus/me4600_ao.c
index 2c92e655a81e..e2bec8229abd 100644
--- a/drivers/staging/meilhaus/me4600_ao.c
+++ b/drivers/staging/meilhaus/me4600_ao.c
@@ -2294,7 +2294,7 @@ static irqreturn_t me4600_ao_isr(int irq, void *dev_id
irq_status = inl(instance->irq_status_reg);
if (!(irq_status & (ME4600_IRQ_STATUS_BIT_AO_HF << instance->ao_idx))) {
PINFO("%ld Shared interrupt. %s(): ID=%d: status_reg=0x%04X\n",
- jiffies, __FUNCTION__, instance->ao_idx, irq_status);
+ jiffies, __func__, instance->ao_idx, irq_status);
return IRQ_NONE;
}
@@ -3009,7 +3009,7 @@ static void me4600_ao_work_control_task(
instance =
container_of((void *)work, me4600_ao_subdevice_t, ao_control_task);
#endif
- PINFO("<%s: %ld> executed. idx=%d\n", __FUNCTION__, jiffies,
+ PINFO("<%s: %ld> executed. idx=%d\n", __func__, jiffies,
instance->ao_idx);
status = inl(instance->status_reg);
@@ -3316,7 +3316,7 @@ static void me4600_ao_work_control_task(
queue_delayed_work(instance->me4600_workqueue,
&instance->ao_control_task, 1);
} else {
- PINFO("<%s> Ending control task.\n", __FUNCTION__);
+ PINFO("<%s> Ending control task.\n", __func__);
}
}
diff --git a/drivers/staging/meilhaus/me4600_ext_irq.c b/drivers/staging/meilhaus/me4600_ext_irq.c
index 8a10dceae32a..adc1e1babf40 100644
--- a/drivers/staging/meilhaus/me4600_ext_irq.c
+++ b/drivers/staging/meilhaus/me4600_ext_irq.c
@@ -356,7 +356,7 @@ static irqreturn_t me4600_ext_irq_isr(int irq, void *dev_id,
irq_status = inl(instance->irq_status_reg);
if (!(irq_status & ME4600_IRQ_STATUS_BIT_EX)) {
PINFO("%ld Shared interrupt. %s(): irq_status_reg=0x%04X\n",
- jiffies, __FUNCTION__, irq_status);
+ jiffies, __func__, irq_status);
return IRQ_NONE;
}
diff --git a/drivers/staging/meilhaus/me6000_ao.c b/drivers/staging/meilhaus/me6000_ao.c
index 3f5ff6d1b991..94f01231f79a 100644
--- a/drivers/staging/meilhaus/me6000_ao.c
+++ b/drivers/staging/meilhaus/me6000_ao.c
@@ -863,7 +863,7 @@ static int me6000_ao_io_single_write(me_subdevice_t * subdevice,
/// @note When flag 'ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS' is set than output is triggered. ALWAYS!
- PINFO("<%s> start mode= 0x%08x %s\n", __FUNCTION__, mode,
+ PINFO("<%s> start mode= 0x%08x %s\n", __func__, mode,
(flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) ? "SYNCHRONOUS" :
"");
if (instance->fifo & ME6000_AO_HAS_FIFO) { // FIFO - Continous mode
@@ -1663,7 +1663,7 @@ static int me6000_ao_io_stream_start(me_subdevice_t * subdevice,
status = inl(instance->status_reg);
//Start state machine and interrupts
- PINFO("<%s:%d> Start state machine.\n", __FUNCTION__, __LINE__);
+ PINFO("<%s:%d> Start state machine.\n", __func__, __LINE__);
ctrl &= ~(ME6000_AO_CTRL_BIT_STOP | ME6000_AO_CTRL_BIT_IMMEDIATE_STOP);
if (instance->start_mode == ME6000_AO_EXT_TRIG) {
PDEBUG("DIGITAL TRIGGER\n");
@@ -1671,7 +1671,7 @@ static int me6000_ao_io_stream_start(me_subdevice_t * subdevice,
}
if (!(status & ME6000_AO_STATUS_BIT_HF)) { //More than half!
if ((ctrl & ME6000_AO_CTRL_MODE_MASK) == ME6000_AO_MODE_CONTINUOUS) { //Enable IRQ only when hardware_continous is set and FIFO is more than half
- PINFO("<%s:%d> Start interrupts.\n", __FUNCTION__,
+ PINFO("<%s:%d> Start interrupts.\n", __func__,
__LINE__);
ctrl |= ME6000_AO_CTRL_BIT_ENABLE_IRQ;
}
@@ -1682,7 +1682,7 @@ static int me6000_ao_io_stream_start(me_subdevice_t * subdevice,
spin_unlock_irqrestore(&instance->subdevice_lock, cpu_flags);
//Trigger output
- PINFO("<%s> start mode= 0x%x %s\n", __FUNCTION__, instance->start_mode,
+ PINFO("<%s> start mode= 0x%x %s\n", __func__, instance->start_mode,
(flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) ? "SYNCHRONOUS" :
"");
if (flags & ME_IO_SINGLE_TYPE_TRIG_SYNCHRONOUS) { //Trigger outputs
@@ -1777,7 +1777,7 @@ static int me6000_ao_io_stream_start(me_subdevice_t * subdevice,
status = inl(instance->status_reg);
if (!(status & ME6000_AO_STATUS_BIT_HF)) { //More than half!
spin_lock_irqsave(&instance->subdevice_lock, cpu_flags);
- PINFO("<%s:%d> Start interrupts.\n", __FUNCTION__,
+ PINFO("<%s:%d> Start interrupts.\n", __func__,
__LINE__);
ctrl = inl(instance->ctrl_reg);
ctrl |= ME6000_AO_CTRL_BIT_ENABLE_IRQ;
@@ -1819,7 +1819,7 @@ static int me6000_ao_io_stream_start(me_subdevice_t * subdevice,
spin_lock_irqsave(&instance->subdevice_lock,
cpu_flags);
PINFO("<%s:%d> Start interrupts.\n",
- __FUNCTION__, __LINE__);
+ __func__, __LINE__);
ctrl = inl(instance->ctrl_reg);
ctrl |= ME6000_AO_CTRL_BIT_ENABLE_IRQ;
outl(ctrl, instance->ctrl_reg);
@@ -2346,7 +2346,7 @@ static irqreturn_t me6000_ao_isr(int irq, void *dev_id, struct pt_regs *regs)
irq_status = inl(instance->irq_status_reg);
if (!(irq_status & (ME6000_IRQ_STATUS_BIT_AO_HF << instance->ao_idx))) {
PINFO("%ld Shared interrupt. %s(): ID=%d: status_reg=0x%04X\n",
- jiffies, __FUNCTION__, instance->ao_idx, irq_status);
+ jiffies, __func__, instance->ao_idx, irq_status);
return IRQ_NONE;
}
@@ -2861,7 +2861,7 @@ int inline ao_stop_immediately(me6000_ao_subdevice_t * instance)
}
}
- PINFO("<%s> Wait for stop: %d\n", __FUNCTION__, i);
+ PINFO("<%s> Wait for stop: %d\n", __func__, i);
//Still working!
set_current_state(TASK_INTERRUPTIBLE);
@@ -3132,7 +3132,7 @@ static void me6000_ao_work_control_task(
instance =
container_of((void *)work, me6000_ao_subdevice_t, ao_control_task);
#endif
- PINFO("<%s: %ld> executed. idx=%d\n", __FUNCTION__, jiffies,
+ PINFO("<%s: %ld> executed. idx=%d\n", __func__, jiffies,
instance->ao_idx);
status = inl(instance->status_reg);
@@ -3550,7 +3550,7 @@ static void me6000_ao_work_control_task(
queue_delayed_work(instance->me6000_workqueue,
&instance->ao_control_task, 1);
} else {
- PINFO("<%s> Ending control task.\n", __FUNCTION__);
+ PINFO("<%s> Ending control task.\n", __func__);
}
}
diff --git a/drivers/staging/meilhaus/me8100_di.c b/drivers/staging/meilhaus/me8100_di.c
index 0f146371b9a0..971727c9e305 100644
--- a/drivers/staging/meilhaus/me8100_di.c
+++ b/drivers/staging/meilhaus/me8100_di.c
@@ -536,7 +536,7 @@ static irqreturn_t me8100_isr(int irq, void *dev_id, struct pt_regs *regs)
PLX_INTCSR_LOCAL_INT1_EN)) {
PINFO
("%ld Shared interrupt. %s(): idx=0 plx:irq_status_reg=0x%04X\n",
- jiffies, __FUNCTION__, icsr);
+ jiffies, __func__, icsr);
return IRQ_NONE;
}
} else if (instance->di_idx == 1) {
@@ -547,11 +547,11 @@ static irqreturn_t me8100_isr(int irq, void *dev_id, struct pt_regs *regs)
PLX_INTCSR_LOCAL_INT2_EN)) {
PINFO
("%ld Shared interrupt. %s(): idx=1 plx:irq_status_reg=0x%04X\n",
- jiffies, __FUNCTION__, icsr);
+ jiffies, __func__, icsr);
return IRQ_NONE;
}
} else {
- PERROR("%s():Wrong interrupt idx=%d csr=0x%X.\n", __FUNCTION__,
+ PERROR("%s():Wrong interrupt idx=%d csr=0x%X.\n", __func__,
instance->di_idx, icsr);
return IRQ_NONE;
}
diff --git a/drivers/staging/meilhaus/me8200_di.c b/drivers/staging/meilhaus/me8200_di.c
index 0bb4567091cc..27525bc067b6 100644
--- a/drivers/staging/meilhaus/me8200_di.c
+++ b/drivers/staging/meilhaus/me8200_di.c
@@ -570,7 +570,7 @@ static irqreturn_t me8200_isr(int irq, void *dev_id, struct pt_regs *regs)
if (!irq_status) {
PINFO
("%ld Shared interrupt. %s(): idx=%d irq_status_reg=0x%04X\n",
- jiffies, __FUNCTION__, instance->di_idx, irq_status);
+ jiffies, __func__, instance->di_idx, irq_status);
return IRQ_NONE;
}
@@ -658,7 +658,7 @@ static irqreturn_t me8200_isr_EX(int irq, void *dev_id, struct pt_regs *regs)
if (!irq_status) {
PINFO
("%ld Shared interrupt. %s(): idx=%d irq_status_reg=0x%04X\n",
- jiffies, __FUNCTION__, instance->di_idx, irq_status);
+ jiffies, __func__, instance->di_idx, irq_status);
return IRQ_NONE;
}
diff --git a/drivers/staging/meilhaus/me8200_do.c b/drivers/staging/meilhaus/me8200_do.c
index 5f4ba5dfa860..d2bebd16ff41 100644
--- a/drivers/staging/meilhaus/me8200_do.c
+++ b/drivers/staging/meilhaus/me8200_do.c
@@ -475,7 +475,7 @@ static irqreturn_t me8200_do_isr(int irq, void *dev_id, struct pt_regs *regs)
(ME8200_DO_IRQ_STATUS_BIT_ACTIVE << instance->do_idx))) {
PINFO
("%ld Shared interrupt. %s(): idx=%d irq_status_reg=0x%04X\n",
- jiffies, __FUNCTION__, instance->do_idx, irq_status);
+ jiffies, __func__, instance->do_idx, irq_status);
return IRQ_NONE;
}
diff --git a/drivers/staging/meilhaus/medebug.h b/drivers/staging/meilhaus/medebug.h
index 382d00fe311d..dcfb97c26fd1 100644
--- a/drivers/staging/meilhaus/medebug.h
+++ b/drivers/staging/meilhaus/medebug.h
@@ -66,21 +66,21 @@
#ifdef MEDEBUG_DEBUG
# define PDEBUG(fmt, args...) \
- printk(KERN_DEBUG"ME_DRV D: <%s> " fmt, __FUNCTION__, ##args)
+ printk(KERN_DEBUG"ME_DRV D: <%s> " fmt, __func__, ##args)
#else
# define PDEBUG(fmt, args...)
#endif
#ifdef MEDEBUG_DEBUG_LOCKS
# define PDEBUG_LOCKS(fmt, args...) \
- printk(KERN_DEBUG"ME_DRV L: <%s> " fmt, __FUNCTION__, ##args)
+ printk(KERN_DEBUG"ME_DRV L: <%s> " fmt, __func__, ##args)
#else
# define PDEBUG_LOCKS(fmt, args...)
#endif
#ifdef MEDEBUG_DEBUG_REG
# define PDEBUG_REG(fmt, args...) \
- printk(KERN_DEBUG"ME_DRV R: <%s:%d> REG:" fmt, __FUNCTION__, __LINE__, ##args)
+ printk(KERN_DEBUG"ME_DRV R: <%s:%d> REG:" fmt, __func__, __LINE__, ##args)
#else
# define PDEBUG_REG(fmt, args...)
#endif
@@ -108,7 +108,7 @@
//This debug is only to detect logical errors!
# define PSECURITY(fmt, args...) \
- printk(KERN_CRIT"ME_DRV SECURITY: <%s:%s:%i> " fmt, __FILE__, __FUNCTION__, __LINE__, ##args)
+ printk(KERN_CRIT"ME_DRV SECURITY: <%s:%s:%i> " fmt, __FILE__, __func__, __LINE__, ##args)
//This debug is to keep track in customers' system
# define PLOG(fmt, args...) \
printk(KERN_INFO"ME_DRV: " fmt, ##args)
@@ -116,7 +116,7 @@
//This debug is to check new parts during development
#ifdef MEDEBUG_DEVELOP
# define PDEVELOP(fmt, args...) \
- printk(KERN_CRIT"ME_DRV: <%s:%s:%i> " fmt, __FILE__, __FUNCTION__, __LINE__, ##args)
+ printk(KERN_CRIT"ME_DRV: <%s:%s:%i> " fmt, __FILE__, __func__, __LINE__, ##args)
#else
# define PDEVELOP(fmt, args...)
#endif
diff --git a/drivers/staging/otus/80211core/cagg.c b/drivers/staging/otus/80211core/cagg.c
index fcfd01a6b36c..4942190747a1 100644
--- a/drivers/staging/otus/80211core/cagg.c
+++ b/drivers/staging/otus/80211core/cagg.c
@@ -1933,7 +1933,7 @@ u16_t zfAggRx(zdev_t* dev, zbuf_t* buf, struct zsAdditionInfo *addInfo, struct a
*/
/* zm_msg2_agg(ZM_LV_0, "queue seq = ", seq_no);
- * DbgPrint("%s:%s%lxh %s%lxh\n", __FUNCTION__, "queue seq=", seq_no,
+ * DbgPrint("%s:%s%lxh %s%lxh\n", __func__, "queue seq=", seq_no,
* "; seq_start=", tid_rx->seq_start);
*/
diff --git a/drivers/staging/otus/80211core/pub_zfw.h b/drivers/staging/otus/80211core/pub_zfw.h
index 01a227216726..2474bb7536e8 100644
--- a/drivers/staging/otus/80211core/pub_zfw.h
+++ b/drivers/staging/otus/80211core/pub_zfw.h
@@ -23,7 +23,7 @@
/* Buffer management */
#ifdef ZM_ENABLE_BUFFER_DEBUG
extern zbuf_t* zfwBufAllocateWithContext(zdev_t* dev, u16_t len, u8_t *functionName, ULONG line);
-#define zfwBufAllocate(dev, len) zfwBufAllocateWithContext(dev, len, (u8_t *)__FUNCTION__, __LINE__)
+#define zfwBufAllocate(dev, len) zfwBufAllocateWithContext(dev, len, (u8_t *)__func__, __LINE__)
#else
extern zbuf_t* zfwBufAllocate(zdev_t* dev, u16_t len);
#endif
diff --git a/drivers/staging/otus/80211core/struct.h b/drivers/staging/otus/80211core/struct.h
index 43631c630a8f..17b5ce37ebb5 100644
--- a/drivers/staging/otus/80211core/struct.h
+++ b/drivers/staging/otus/80211core/struct.h
@@ -137,7 +137,7 @@ extern const u8_t zg11gRateTbl[8];
#ifdef ZM_ENABLE_BUFFER_TRACE
extern void zfwBufTrace(zdev_t* dev, zbuf_t *buf, u8_t *functionName);
-#define ZM_BUFFER_TRACE(dev, buf) zfwBufTrace(dev, buf, __FUNCTION__);
+#define ZM_BUFFER_TRACE(dev, buf) zfwBufTrace(dev, buf, __func__);
#else
#define ZM_BUFFER_TRACE(dev, buf)
#endif
diff --git a/drivers/staging/otus/oal_marc.h b/drivers/staging/otus/oal_marc.h
index 438e4bc2e9a6..206111616a03 100644
--- a/drivers/staging/otus/oal_marc.h
+++ b/drivers/staging/otus/oal_marc.h
@@ -106,14 +106,14 @@
/***** Debug message *****/
#if 0
-#define zm_debug_msg0(msg) printk("%s:%s\n", __FUNCTION__, msg);
-#define zm_debug_msg1(msg, val) printk("%s:%s%ld\n", __FUNCTION__, \
+#define zm_debug_msg0(msg) printk("%s:%s\n", __func__, msg);
+#define zm_debug_msg1(msg, val) printk("%s:%s%ld\n", __func__, \
msg, (u32_t)val);
-#define zm_debug_msg2(msg, val) printk("%s:%s%lxh\n", __FUNCTION__, \
+#define zm_debug_msg2(msg, val) printk("%s:%s%lxh\n", __func__, \
msg, (u32_t)val);
-#define zm_debug_msg_s(msg, val) printk("%s:%s%s\n", __FUNCTION__, \
+#define zm_debug_msg_s(msg, val) printk("%s:%s%s\n", __func__, \
msg, val);
-#define zm_debug_msg_p(msg, val1, val2) printk("%s:%s%01ld.%02ld\n", __FUNCTION__, \
+#define zm_debug_msg_p(msg, val1, val2) printk("%s:%s%01ld.%02ld\n", __func__, \
msg, (val1/val2), (((val1*100)/val2)%100));
#define zm_dbg(S) printk S
#else
@@ -127,7 +127,7 @@
#define zm_assert(expr) if(!(expr)) { \
printk( "Atheors Assertion failed! %s,%s,%s,line=%d\n", \
- #expr,__FILE__,__FUNCTION__,__LINE__); \
+ #expr,__FILE__,__func__,__LINE__); \
}
#define DbgPrint printk
diff --git a/drivers/staging/rt2860/2860_main_dev.c b/drivers/staging/rt2860/2860_main_dev.c
index 1e38f2d1f692..08ca81f43cc8 100644
--- a/drivers/staging/rt2860/2860_main_dev.c
+++ b/drivers/staging/rt2860/2860_main_dev.c
@@ -1202,7 +1202,7 @@ VOID RT28xx_UpdateBeaconToAsic(
UCHAR bcn_idx = 0;
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s() : No valid Interface be found.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s() : No valid Interface be found.\n", __func__));
return;
}
diff --git a/drivers/staging/rt2860/common/ba_action.c b/drivers/staging/rt2860/common/ba_action.c
index 8247aeb73a23..591d1e2158da 100644
--- a/drivers/staging/rt2860/common/ba_action.c
+++ b/drivers/staging/rt2860/common/ba_action.c
@@ -599,7 +599,7 @@ VOID BAOriSessionAdd(
pBAEntry->ORIBATimer.TimerValue = 0; //pFrame->TimeOutValue;
- DBGPRINT(RT_DEBUG_TRACE,("%s : TXBAbitmap = %x, BAWinSize = %d, TimeOut = %ld\n", __FUNCTION__, pEntry->TXBAbitmap,
+ DBGPRINT(RT_DEBUG_TRACE,("%s : TXBAbitmap = %x, BAWinSize = %d, TimeOut = %ld\n", __func__, pEntry->TXBAbitmap,
pBAEntry->BAWinSize, pBAEntry->ORIBATimer.TimerValue));
// SEND BAR ;
@@ -673,7 +673,7 @@ BOOLEAN BARecSessionAdd(
ba_refresh_reordering_mpdus(pAd, pBAEntry);
}
- DBGPRINT(RT_DEBUG_TRACE,("%s(%ld): Idx = %d, BAWinSize(req %d) = %d\n", __FUNCTION__, pAd->BATable.numAsRecipient, Idx,
+ DBGPRINT(RT_DEBUG_TRACE,("%s(%ld): Idx = %d, BAWinSize(req %d) = %d\n", __func__, pAd->BATable.numAsRecipient, Idx,
pFrame->BaParm.BufSize, BAWinSize));
// Start fill in parameters.
@@ -915,7 +915,7 @@ VOID BAOriSessionTearDown(
return;
}
- DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID));
+ DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __func__, Wcid, TID));
pBAEntry = &pAd->BATable.BAOriEntry[Idx];
DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, ORI_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->ORI_BA_Status));
@@ -974,7 +974,7 @@ VOID BARecSessionTearDown(
if (Idx == 0)
return;
- DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID));
+ DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __func__, Wcid, TID));
pBAEntry = &pAd->BATable.BARecEntry[Idx];
@@ -1185,7 +1185,7 @@ VOID PeerAddBAReqAction(
PULONG ptemp;
PMAC_TABLE_ENTRY pMacEntry;
- DBGPRINT(RT_DEBUG_TRACE, ("%s ==> (Wcid = %d)\n", __FUNCTION__, Elem->Wcid));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s ==> (Wcid = %d)\n", __func__, Elem->Wcid));
//hex_dump("AddBAReq", Elem->Msg, Elem->MsgLen);
@@ -1269,7 +1269,7 @@ VOID PeerAddBAReqAction(
MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
- DBGPRINT(RT_DEBUG_TRACE, ("%s(%d): TID(%d), BufSize(%d) <== \n", __FUNCTION__, Elem->Wcid, ADDframe.BaParm.TID,
+ DBGPRINT(RT_DEBUG_TRACE, ("%s(%d): TID(%d), BufSize(%d) <== \n", __func__, Elem->Wcid, ADDframe.BaParm.TID,
ADDframe.BaParm.BufSize));
}
@@ -1288,7 +1288,7 @@ VOID PeerAddBARspAction(
if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE)
return;
- DBGPRINT(RT_DEBUG_TRACE, ("%s ==> Wcid(%d)\n", __FUNCTION__, Elem->Wcid));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s ==> Wcid(%d)\n", __func__, Elem->Wcid));
//hex_dump("PeerAddBARspAction()", Elem->Msg, Elem->MsgLen);
@@ -1329,7 +1329,7 @@ VOID PeerDelBAAction(
//PUCHAR pOutBuffer = NULL;
PFRAME_DELBA_REQ pDelFrame = NULL;
- DBGPRINT(RT_DEBUG_TRACE,("%s ==>\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE,("%s ==>\n", __func__));
//DELBA Request from unknown peer, ignore this.
if (PeerDelBAActionSanity(pAd, Elem->Wcid, Elem->Msg, Elem->MsgLen))
{
@@ -1366,7 +1366,7 @@ BOOLEAN CntlEnqueueForRecv(
TID = (UCHAR)pFrame->BARControl.TID;
- DBGPRINT(RT_DEBUG_TRACE, ("%s(): BAR-Wcid(%ld), Tid (%d)\n", __FUNCTION__, Wcid, TID));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s(): BAR-Wcid(%ld), Tid (%d)\n", __func__, Wcid, TID));
//hex_dump("BAR", (PCHAR) pFrame, MsgLen);
// Do nothing if the driver is starting halt state.
// This might happen when timer already been fired before cancel timer with mlmehalt
diff --git a/drivers/staging/rt2860/common/cmm_data.c b/drivers/staging/rt2860/common/cmm_data.c
index ac549011ccb9..b67b9eba7229 100644
--- a/drivers/staging/rt2860/common/cmm_data.c
+++ b/drivers/staging/rt2860/common/cmm_data.c
@@ -2787,7 +2787,7 @@ BOOLEAN MacTableDeleteEntry(
}
else
{
- printk("\n%s: Impossible Wcid = %d !!!!!\n", __FUNCTION__, wcid);
+ printk("\n%s: Impossible Wcid = %d !!!!!\n", __func__, wcid);
}
}
diff --git a/drivers/staging/rt2860/common/cmm_data_2860.c b/drivers/staging/rt2860/common/cmm_data_2860.c
index 4f414edd658c..419e50c3fc4c 100644
--- a/drivers/staging/rt2860/common/cmm_data_2860.c
+++ b/drivers/staging/rt2860/common/cmm_data_2860.c
@@ -1002,7 +1002,7 @@ VOID RT28xxPciStaAsicSleepThenAutoWakeup(
AutoWakeupCfg.field.AutoLeadTime = 5;
RTMP_IO_WRITE32(pAd, AUTO_WAKEUP_CFG, AutoWakeupCfg.word);
AsicSendCommandToMcu(pAd, 0x30, 0xff, 0xff, 0x00); // send POWER-SAVE command to MCU. Timeout 40us.
- DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __FUNCTION__, TbttNumToNextWakeUp));
+ DBGPRINT(RT_DEBUG_TRACE, ("<-- %s, TbttNumToNextWakeUp=%d \n", __func__, TbttNumToNextWakeUp));
}
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_DOZE);
}
@@ -1115,7 +1115,7 @@ VOID RT28xxPciMlmeRadioOn(
if (!RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
return;
- DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
if ((pAd->OpMode == OPMODE_AP) ||
((pAd->OpMode == OPMODE_STA) && (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))))
@@ -1165,7 +1165,7 @@ VOID RT28xxPciMlmeRadioOFF(
if (RTMP_TEST_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF))
return;
- DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
// Set LED
RTMPSetLED(pAd, LED_RADIO_OFF);
diff --git a/drivers/staging/rt2860/common/cmm_info.c b/drivers/staging/rt2860/common/cmm_info.c
index 0aadf8af633a..dd92ac6eaed2 100644
--- a/drivers/staging/rt2860/common/cmm_info.c
+++ b/drivers/staging/rt2860/common/cmm_info.c
@@ -2039,7 +2039,7 @@ VOID RTMPIoctlGetMacTable(
wrq->u.data.length = sizeof(RT_802_11_MAC_TABLE);
if (copy_to_user(wrq->u.data.pointer, &MacTab, wrq->u.data.length))
{
- DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __func__));
}
msg = (CHAR *) kmalloc(sizeof(CHAR)*(MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN), MEM_ALLOC_FLAG);
diff --git a/drivers/staging/rt2860/common/dfs.c b/drivers/staging/rt2860/common/dfs.c
index 23cf1510e2d2..b09bba5cb206 100644
--- a/drivers/staging/rt2860/common/dfs.c
+++ b/drivers/staging/rt2860/common/dfs.c
@@ -428,7 +428,7 @@ INT Set_ChMovingTime_Proc(
pAd->CommonCfg.RadarDetect.ChMovingTime = Value;
- DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__,
+ DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __func__,
pAd->CommonCfg.RadarDetect.ChMovingTime));
return TRUE;
@@ -444,7 +444,7 @@ INT Set_LongPulseRadarTh_Proc(
pAd->CommonCfg.RadarDetect.LongPulseRadarTh = Value;
- DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__,
+ DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __func__,
pAd->CommonCfg.RadarDetect.LongPulseRadarTh));
return TRUE;
diff --git a/drivers/staging/rt2860/common/rtmp_init.c b/drivers/staging/rt2860/common/rtmp_init.c
index 84edfa52dec3..563f2c5bb856 100644
--- a/drivers/staging/rt2860/common/rtmp_init.c
+++ b/drivers/staging/rt2860/common/rtmp_init.c
@@ -2542,7 +2542,7 @@ NDIS_STATUS NICLoadFirmware(
#ifdef BIN_IN_FILE
#define NICLF_DEFAULT_USE() \
flg_default_firm_use = TRUE; \
- printk("%s - Use default firmware!\n", __FUNCTION__);
+ printk("%s - Use default firmware!\n", __func__);
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PUCHAR src;
@@ -2557,7 +2557,7 @@ NDIS_STATUS NICLoadFirmware(
BOOLEAN flg_default_firm_use = FALSE;
- DBGPRINT(RT_DEBUG_TRACE, ("===> %s\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("===> %s\n", __func__));
/* init */
pFirmwareImage = NULL;
@@ -2580,7 +2580,7 @@ NDIS_STATUS NICLoadFirmware(
if (pFirmwareImage == NULL)
{
/* allocate fail, use default firmware array in firmware.h */
- printk("%s - Allocate memory fail!\n", __FUNCTION__);
+ printk("%s - Allocate memory fail!\n", __func__);
NICLF_DEFAULT_USE();
}
else
@@ -2601,7 +2601,7 @@ NDIS_STATUS NICLoadFirmware(
if (IS_ERR(srcf))
{
printk("%s - Error %ld opening %s\n",
- __FUNCTION__, -PTR_ERR(srcf), src);
+ __func__, -PTR_ERR(srcf), src);
NICLF_DEFAULT_USE();
break;
} /* End of if */
@@ -2609,7 +2609,7 @@ NDIS_STATUS NICLoadFirmware(
/* the object must have a read method */
if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL))
{
- printk("%s - %s does not have a write method\n", __FUNCTION__, src);
+ printk("%s - %s does not have a write method\n", __func__, src);
NICLF_DEFAULT_USE();
break;
} /* End of if */
@@ -2623,7 +2623,7 @@ NDIS_STATUS NICLoadFirmware(
if (FileLength != MAX_FIRMWARE_IMAGE_SIZE)
{
printk("%s: error file length (=%d) in RT2860AP.BIN\n",
- __FUNCTION__, FileLength);
+ __func__, FileLength);
NICLF_DEFAULT_USE();
break;
}
@@ -2646,7 +2646,7 @@ NDIS_STATUS NICLoadFirmware(
/* CRC fail */
printk("%s: CRC = 0x%02x 0x%02x "
"error, should be 0x%02x 0x%02x\n",
- __FUNCTION__,
+ __func__,
pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2],
pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1],
(UCHAR)(crc>>8), (UCHAR)(crc));
@@ -2665,7 +2665,7 @@ NDIS_STATUS NICLoadFirmware(
((FIRMWARE_MAJOR_VERSION << 8) +
FIRMWARE_MINOR_VERSION))
{
- printk("%s: firmware version too old!\n", __FUNCTION__);
+ printk("%s: firmware version too old!\n", __func__);
NICLF_DEFAULT_USE();
break;
} /* End of if */
@@ -2770,7 +2770,7 @@ NDIS_STATUS NICLoadFirmware(
} /* End of if */
DBGPRINT(RT_DEBUG_TRACE,
- ("<=== %s (status=%d)\n", __FUNCTION__, Status));
+ ("<=== %s (status=%d)\n", __func__, Status));
return Status;
} /* End of NICLoadFirmware */
diff --git a/drivers/staging/rt2860/common/spectrum.c b/drivers/staging/rt2860/common/spectrum.c
index 85e636a607f7..0265a6d1df1a 100644
--- a/drivers/staging/rt2860/common/spectrum.c
+++ b/drivers/staging/rt2860/common/spectrum.c
@@ -49,7 +49,7 @@ VOID MeasureReqTabInit(
if (pAd->CommonCfg.pMeasureReqTab)
NdisZeroMemory(pAd->CommonCfg.pMeasureReqTab, sizeof(MEASURE_REQ_TAB));
else
- DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", __func__));
return;
}
@@ -77,7 +77,7 @@ static PMEASURE_REQ_ENTRY MeasureReqLookUp(
if (pTab == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__));
return NULL;
}
@@ -114,7 +114,7 @@ static PMEASURE_REQ_ENTRY MeasureReqInsert(
if(pTab == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__));
return NULL;
}
@@ -175,7 +175,7 @@ static PMEASURE_REQ_ENTRY MeasureReqInsert(
else
{
pEntry = NULL;
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab tab full.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab tab full.\n", __func__));
}
// add this Neighbor entry into HASH table
@@ -210,7 +210,7 @@ static VOID MeasureReqDelete(
if(pTab == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__));
return;
}
@@ -267,7 +267,7 @@ VOID TpcReqTabInit(
if (pAd->CommonCfg.pTpcReqTab)
NdisZeroMemory(pAd->CommonCfg.pTpcReqTab, sizeof(TPC_REQ_TAB));
else
- DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", __func__));
return;
}
@@ -295,7 +295,7 @@ static PTPC_REQ_ENTRY TpcReqLookUp(
if (pTab == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__));
return NULL;
}
@@ -333,7 +333,7 @@ static PTPC_REQ_ENTRY TpcReqInsert(
if(pTab == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__));
return NULL;
}
@@ -394,7 +394,7 @@ static PTPC_REQ_ENTRY TpcReqInsert(
else
{
pEntry = NULL;
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab tab full.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab tab full.\n", __func__));
}
// add this Neighbor entry into HASH table
@@ -429,7 +429,7 @@ static VOID TpcReqDelete(
if(pTab == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__));
return;
}
@@ -782,7 +782,7 @@ VOID EnqueueMeasurementReq(
NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory
if(NStatus != NDIS_STATUS_SUCCESS)
{
- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
return;
}
NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
@@ -844,7 +844,7 @@ VOID EnqueueMeasurementRep(
NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory
if(NStatus != NDIS_STATUS_SUCCESS)
{
- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
return;
}
NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
@@ -898,7 +898,7 @@ VOID EnqueueTPCReq(
NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory
if(NStatus != NDIS_STATUS_SUCCESS)
{
- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
return;
}
NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
@@ -950,7 +950,7 @@ VOID EnqueueTPCRep(
NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory
if(NStatus != NDIS_STATUS_SUCCESS)
{
- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
return;
}
NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
@@ -1003,7 +1003,7 @@ VOID EnqueueChSwAnn(
NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory
if(NStatus != NDIS_STATUS_SUCCESS)
{
- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
return;
}
NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
@@ -1596,7 +1596,7 @@ static VOID PeerMeasureReportAction(
if ((pMeasureReportInfo = kmalloc(sizeof(MEASURE_RPI_REPORT), GFP_ATOMIC)) == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%d).\n", __FUNCTION__, sizeof(MEASURE_RPI_REPORT)));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%d).\n", __func__, sizeof(MEASURE_RPI_REPORT)));
return;
}
@@ -1705,7 +1705,7 @@ static VOID PeerTpcRepAction(
{
TpcReqDelete(pAd, pEntry->DialogToken);
DBGPRINT(RT_DEBUG_TRACE, ("%s: DialogToken=%x, TxPwr=%d, LinkMargin=%d\n",
- __FUNCTION__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin));
+ __func__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin));
}
}
@@ -1821,7 +1821,7 @@ INT Set_MeasureReq_Proc(
MeasureReqType = simple_strtol(thisChar, 0, 16);
if (MeasureReqType > 3)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __FUNCTION__, MeasureReqType));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __func__, MeasureReqType));
return TRUE;
}
break;
@@ -1833,10 +1833,10 @@ INT Set_MeasureReq_Proc(
ArgIdx++;
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __FUNCTION__, Aid, MeasureReqType, MeasureCh));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __func__, Aid, MeasureReqType, MeasureCh));
if (!VALID_WCID(Aid))
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, Aid));
return TRUE;
}
@@ -1861,10 +1861,10 @@ INT Set_TpcReq_Proc(
Aid = simple_strtol(arg, 0, 16);
- DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __FUNCTION__, Aid));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __func__, Aid));
if (!VALID_WCID(Aid))
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, Aid));
return TRUE;
}
diff --git a/drivers/staging/rt2860/rt_ate.c b/drivers/staging/rt2860/rt_ate.c
index 2f07db565c30..f3316ec0b156 100644
--- a/drivers/staging/rt2860/rt_ate.c
+++ b/drivers/staging/rt2860/rt_ate.c
@@ -291,7 +291,7 @@ static INT ATETxPwrHandler(
Bbp94 = BBPR94_DEFAULT;
}
- ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94));
+ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%ld, BBP_R94=%d)\n", __func__, TxPower, R, Bbp94));
}
else// 5.5 GHz
{
@@ -318,7 +318,7 @@ static INT ATETxPwrHandler(
R = (ULONG) TxPower;
}
- ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%lu)\n", __FUNCTION__, TxPower, R));
+ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%lu)\n", __func__, TxPower, R));
}
if (pAd->ate.Channel <= 14)
@@ -431,7 +431,7 @@ static INT ATETxPwrHandler(
Bbp94 = BBPR94_DEFAULT;
}
- ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R3=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94));
+ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R3=%ld, BBP_R94=%d)\n", __func__, TxPower, R, Bbp94));
if (pAd->ate.Channel <= 14)
{
@@ -2098,7 +2098,7 @@ INT Set_ATE_Load_E2P_Proc(
UINT32 FileLength = 0;
UINT32 value = simple_strtol(arg, 0, 10);
- ATEDBGPRINT(RT_DEBUG_ERROR, ("===> %s (value=%d)\n\n", __FUNCTION__, value));
+ ATEDBGPRINT(RT_DEBUG_ERROR, ("===> %s (value=%d)\n\n", __func__, value));
if (value > 0)
{
@@ -2122,14 +2122,14 @@ INT Set_ATE_Load_E2P_Proc(
if (IS_ERR(srcf))
{
- ate_print("%s - Error %ld opening %s\n", __FUNCTION__, -PTR_ERR(srcf), src);
+ ate_print("%s - Error %ld opening %s\n", __func__, -PTR_ERR(srcf), src);
break;
}
/* the object must have a read method */
if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL))
{
- ate_print("%s - %s does not have a read method\n", __FUNCTION__, src);
+ ate_print("%s - %s does not have a read method\n", __func__, src);
break;
}
@@ -2142,7 +2142,7 @@ INT Set_ATE_Load_E2P_Proc(
if (FileLength != EEPROM_SIZE)
{
ate_print("%s: error file length (=%d) in e2p.bin\n",
- __FUNCTION__, FileLength);
+ __func__, FileLength);
break;
}
else
@@ -2174,7 +2174,7 @@ INT Set_ATE_Load_E2P_Proc(
current->fsuid = orgfsuid;
current->fsgid = orgfsgid;
}
- ATEDBGPRINT(RT_DEBUG_ERROR, ("<=== %s (ret=%d)\n", __FUNCTION__, ret));
+ ATEDBGPRINT(RT_DEBUG_ERROR, ("<=== %s (ret=%d)\n", __func__, ret));
return ret;
@@ -2187,12 +2187,12 @@ INT Set_ATE_Load_E2P_Proc(
USHORT WriteEEPROM[(EEPROM_SIZE/2)];
struct iwreq *wrq = (struct iwreq *)arg;
- ATEDBGPRINT(RT_DEBUG_TRACE, ("===> %s (wrq->u.data.length = %d)\n\n", __FUNCTION__, wrq->u.data.length));
+ ATEDBGPRINT(RT_DEBUG_TRACE, ("===> %s (wrq->u.data.length = %d)\n\n", __func__, wrq->u.data.length));
if (wrq->u.data.length != EEPROM_SIZE)
{
ate_print("%s: error length (=%d) from host\n",
- __FUNCTION__, wrq->u.data.length);
+ __func__, wrq->u.data.length);
return FALSE;
}
else/* (wrq->u.data.length == EEPROM_SIZE) */
@@ -2211,7 +2211,7 @@ INT Set_ATE_Load_E2P_Proc(
} while(FALSE);
}
- ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== %s\n", __FUNCTION__));
+ ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== %s\n", __func__));
return TRUE;
@@ -3353,7 +3353,7 @@ static INT ATESetUpFrame(
if (pPacket == NULL)
{
pAd->ate.TxCount = 0;
- ATEDBGPRINT(RT_DEBUG_TRACE, ("%s fail to alloc packet space.\n", __FUNCTION__));
+ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s fail to alloc packet space.\n", __func__));
return -1;
}
pTxRing->Cell[TxIdx].pNextNdisPacket = pPacket;
@@ -3646,7 +3646,7 @@ VOID RtmpDoAte(
Command_Id = ntohs(pRaCfg->command_id);
- ATEDBGPRINT(RT_DEBUG_TRACE,("\n%s: Command_Id = 0x%04x !\n", __FUNCTION__, Command_Id));
+ ATEDBGPRINT(RT_DEBUG_TRACE,("\n%s: Command_Id = 0x%04x !\n", __func__, Command_Id));
switch (Command_Id)
{
@@ -5690,7 +5690,7 @@ BOOLEAN SyncTxRxConfig(PRTMP_ADAPTER pAd, USHORT offset, UCHAR value)
pAd->ate.TxAntennaSel = 2;
break;
default:
- DBGPRINT(RT_DEBUG_TRACE, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s -- Sth. wrong! : return FALSE; \n", __func__));
return FALSE;
}
break;/* case BBP_R1 */
@@ -5728,13 +5728,13 @@ BOOLEAN SyncTxRxConfig(PRTMP_ADAPTER pAd, USHORT offset, UCHAR value)
pAd->ate.RxAntennaSel = 3;
break;
default:
- DBGPRINT(RT_DEBUG_ERROR, ("%s -- Impossible! : return FALSE; \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s -- Impossible! : return FALSE; \n", __func__));
return FALSE;
}
break;/* case BBP_R3 */
default:
- DBGPRINT(RT_DEBUG_ERROR, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s -- Sth. wrong! : return FALSE; \n", __func__));
return FALSE;
}
diff --git a/drivers/staging/rt2860/rt_linux.c b/drivers/staging/rt2860/rt_linux.c
index 374c174c88ee..f14500931efb 100644
--- a/drivers/staging/rt2860/rt_linux.c
+++ b/drivers/staging/rt2860/rt_linux.c
@@ -406,7 +406,7 @@ NDIS_STATUS RTMPAllocateNdisPacket(
skb_put(GET_OS_PKT_TYPE(pPacket), HeaderLen+DataLen);
RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS);
-// printk("%s : pPacket = %p, len = %d\n", __FUNCTION__, pPacket, GET_OS_PKT_LEN(pPacket));
+// printk("%s : pPacket = %p, len = %d\n", __func__, pPacket, GET_OS_PKT_LEN(pPacket));
*ppPacket = pPacket;
return NDIS_STATUS_SUCCESS;
}
@@ -773,13 +773,13 @@ VOID RTMPSendWirelessEvent(
if (event_table_len == 0)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s : The type(%0x02x) is not valid.\n", __FUNCTION__, type));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : The type(%0x02x) is not valid.\n", __func__, type));
return;
}
if (event >= event_table_len)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s : The event(%0x02x) is not valid.\n", __FUNCTION__, event));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : The event(%0x02x) is not valid.\n", __func__, event));
return;
}
@@ -817,14 +817,14 @@ VOID RTMPSendWirelessEvent(
//send wireless event
wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, pBuf);
- //DBGPRINT(RT_DEBUG_TRACE, ("%s : %s\n", __FUNCTION__, pBuf));
+ //DBGPRINT(RT_DEBUG_TRACE, ("%s : %s\n", __func__, pBuf));
kfree(pBuf);
}
else
- DBGPRINT(RT_DEBUG_ERROR, ("%s : Can't allocate memory for wireless event.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : Can't allocate memory for wireless event.\n", __func__));
#else
- DBGPRINT(RT_DEBUG_ERROR, ("%s : The Wireless Extension MUST be v15 or newer.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : The Wireless Extension MUST be v15 or newer.\n", __func__));
#endif /* WIRELESS_EXT >= 15 */
}
@@ -848,13 +848,13 @@ void send_monitor_packets(
ASSERT(pRxBlk->pRxPacket);
if (pRxBlk->DataSize < 10)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too small! (%d)\n", __FUNCTION__, pRxBlk->DataSize));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too small! (%d)\n", __func__, pRxBlk->DataSize));
goto err_free_sk_buff;
}
if (pRxBlk->DataSize + sizeof(wlan_ng_prism2_header) > RX_BUFFER_AGGRESIZE)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%d)\n", __FUNCTION__, pRxBlk->DataSize + sizeof(wlan_ng_prism2_header)));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%d)\n", __func__, pRxBlk->DataSize + sizeof(wlan_ng_prism2_header)));
goto err_free_sk_buff;
}
@@ -910,7 +910,7 @@ void send_monitor_packets(
if (skb_headroom(pOSPkt) < (sizeof(wlan_ng_prism2_header)+ header_len)) {
if (pskb_expand_head(pOSPkt, (sizeof(wlan_ng_prism2_header) + header_len), 0, GFP_ATOMIC)) {
- DBGPRINT(RT_DEBUG_ERROR, ("%s : Reallocate header size of sk_buff fail!\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : Reallocate header size of sk_buff fail!\n", __func__));
goto err_free_sk_buff;
} //end if
} //end if
diff --git a/drivers/staging/rt2860/rt_linux.h b/drivers/staging/rt2860/rt_linux.h
index 0cc7cf23d762..0fd58f5109f2 100644
--- a/drivers/staging/rt2860/rt_linux.h
+++ b/drivers/staging/rt2860/rt_linux.h
@@ -131,7 +131,7 @@ typedef int (*HARD_START_XMIT_FUNC)(struct sk_buff *skb, struct net_device *net_
#define RT_MOD_INC_USE_COUNT() \
if (!try_module_get(THIS_MODULE)) \
{ \
- DBGPRINT(RT_DEBUG_ERROR, ("%s: cannot reserve module\n", __FUNCTION__)); \
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: cannot reserve module\n", __func__)); \
return -1; \
}
diff --git a/drivers/staging/rt2860/rt_profile.c b/drivers/staging/rt2860/rt_profile.c
index cd7ffc8a6e8a..326a3cb52b9c 100644
--- a/drivers/staging/rt2860/rt_profile.c
+++ b/drivers/staging/rt2860/rt_profile.c
@@ -1024,7 +1024,7 @@ NDIS_STATUS RTMPReadParametersHook(
pAd->MlmeAux.SsidLen = pAd->CommonCfg.SsidLen;
NdisZeroMemory(pAd->MlmeAux.Ssid, NDIS_802_11_LENGTH_SSID);
NdisMoveMemory(pAd->MlmeAux.Ssid, tmpbuf, pAd->MlmeAux.SsidLen);
- DBGPRINT(RT_DEBUG_TRACE, ("%s::(SSID=%s)\n", __FUNCTION__, tmpbuf));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::(SSID=%s)\n", __func__, tmpbuf));
}
}
}
@@ -1043,7 +1043,7 @@ NDIS_STATUS RTMPReadParametersHook(
pAd->StaCfg.BssType = BSS_INFRA;
// Reset Ralink supplicant to not use, it will be set to start when UI set PMK key
pAd->StaCfg.WpaState = SS_NOTUSE;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::(NetworkType=%d)\n", __FUNCTION__, pAd->StaCfg.BssType));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::(NetworkType=%d)\n", __func__, pAd->StaCfg.BssType));
}
}
#endif // CONFIG_STA_SUPPORT //
@@ -1337,7 +1337,7 @@ NDIS_STATUS RTMPReadParametersHook(
pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __func__, pAd->StaCfg.WepStatus));
}
#endif // CONFIG_STA_SUPPORT //
}
@@ -1363,7 +1363,7 @@ NDIS_STATUS RTMPReadParametersHook(
pAd->StaCfg.OrigWepStatus = pAd->StaCfg.WepStatus;
pAd->StaCfg.bMixCipher = FALSE;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __func__, pAd->StaCfg.WepStatus));
}
#endif // CONFIG_STA_SUPPORT //
}
@@ -1400,7 +1400,7 @@ NDIS_STATUS RTMPReadParametersHook(
else
{
err = 1;
- DBGPRINT(RT_DEBUG_ERROR, ("%s::(WPAPSK key-string required 8 ~ 64 characters!)\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s::(WPAPSK key-string required 8 ~ 64 characters!)\n", __func__));
}
if (err == 0)
@@ -1416,7 +1416,7 @@ NDIS_STATUS RTMPReadParametersHook(
pAd->StaCfg.WpaState = SS_NOTUSE;
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::(WPAPSK=%s)\n", __FUNCTION__, tmpbuf));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::(WPAPSK=%s)\n", __func__, tmpbuf));
}
}
}
diff --git a/drivers/staging/rt2860/rtmp_def.h b/drivers/staging/rt2860/rtmp_def.h
index bb6f37b0bdc2..be982147883f 100644
--- a/drivers/staging/rt2860/rtmp_def.h
+++ b/drivers/staging/rt2860/rtmp_def.h
@@ -333,7 +333,7 @@
/* sanity check for apidx */
#define MBSS_MR_APIDX_SANITY_CHECK(apidx) \
{ if (apidx > MAX_MBSSID_NUM) { \
- printk("%s> Error! apidx = %d > MAX_MBSSID_NUM!\n", __FUNCTION__, apidx); \
+ printk("%s> Error! apidx = %d > MAX_MBSSID_NUM!\n", __func__, apidx); \
apidx = MAIN_MBSSID; } }
#define VALID_WCID(_wcid) ((_wcid) > 0 && (_wcid) < MAX_LEN_OF_MAC_TABLE )
diff --git a/drivers/staging/rt2860/sta_ioctl.c b/drivers/staging/rt2860/sta_ioctl.c
index 9347d11b586e..3ea2b2c4ab0e 100644
--- a/drivers/staging/rt2860/sta_ioctl.c
+++ b/drivers/staging/rt2860/sta_ioctl.c
@@ -2200,7 +2200,7 @@ rt_private_show(struct net_device *dev, struct iw_request_info *info,
}
break;
default:
- DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __FUNCTION__, subcmd));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __func__, subcmd));
break;
}
@@ -2219,7 +2219,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
MLME_DISASSOC_REQ_STRUCT DisAssocReq;
MLME_DEAUTH_REQ_STRUCT DeAuthReq;
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __func__));
if (pMlme == NULL)
return -EINVAL;
@@ -2228,7 +2228,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
{
#ifdef IW_MLME_DEAUTH
case IW_MLME_DEAUTH:
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __func__));
COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid);
DeAuthReq.Reason = pMlme->reason_code;
MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT);
@@ -2243,7 +2243,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
#endif // IW_MLME_DEAUTH //
#ifdef IW_MLME_DISASSOC
case IW_MLME_DISASSOC:
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __func__));
COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid);
DisAssocReq.Reason = pMlme->reason_code;
@@ -2257,7 +2257,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
break;
#endif // IW_MLME_DISASSOC //
default:
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __func__));
break;
}
@@ -2290,7 +2290,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
else if (param->value == IW_AUTH_WPA_VERSION_WPA2)
pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_CIPHER_PAIRWISE:
if (param->value == IW_AUTH_CIPHER_NONE)
@@ -2321,7 +2321,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus;
pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled;
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_CIPHER_GROUP:
if (param->value == IW_AUTH_CIPHER_NONE)
@@ -2341,7 +2341,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
{
pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled;
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_KEY_MGMT:
if (param->value == IW_AUTH_KEY_MGMT_802_1X)
@@ -2370,12 +2370,12 @@ int rt_ioctl_siwauth(struct net_device *dev,
{
STA_PORT_SECURED(pAdapter);
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
break;
case IW_AUTH_PRIVACY_INVOKED:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_DROP_UNENCRYPTED:
if (param->value != 0)
@@ -2384,7 +2384,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
{
STA_PORT_SECURED(pAdapter);
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_80211_AUTH_ALG:
if (param->value & IW_AUTH_ALG_SHARED_KEY)
@@ -2397,10 +2397,10 @@ int rt_ioctl_siwauth(struct net_device *dev,
}
else
return -EINVAL;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_WPA_ENABLED:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __func__, param->value));
break;
default:
return -EOPNOTSUPP;
@@ -2508,7 +2508,7 @@ int rt_ioctl_siwencodeext(struct net_device *dev,
pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE;
AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx);
NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY));
- DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __FUNCTION__, encoding->flags));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __func__, encoding->flags));
}
else
{
@@ -2520,15 +2520,15 @@ int rt_ioctl_siwencodeext(struct net_device *dev,
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
{
pAdapter->StaCfg.DefaultKeyId = keyIdx;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __FUNCTION__, pAdapter->StaCfg.DefaultKeyId));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __func__, pAdapter->StaCfg.DefaultKeyId));
}
switch (alg) {
case IW_ENCODE_ALG_NONE:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __func__));
break;
case IW_ENCODE_ALG_WEP:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __FUNCTION__, ext->key_len, keyIdx));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __func__, ext->key_len, keyIdx));
if (ext->key_len == MAX_WEP_KEY_SIZE)
{
pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE;
@@ -2546,7 +2546,7 @@ int rt_ioctl_siwencodeext(struct net_device *dev,
NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len);
break;
case IW_ENCODE_ALG_TKIP:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __FUNCTION__, keyIdx, ext->key_len));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __func__, keyIdx, ext->key_len));
if (ext->key_len == 32)
{
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
diff --git a/drivers/staging/rt2870/2870_main_dev.c b/drivers/staging/rt2870/2870_main_dev.c
index 91da4e2298ac..04c764d95d77 100644
--- a/drivers/staging/rt2870/2870_main_dev.c
+++ b/drivers/staging/rt2870/2870_main_dev.c
@@ -263,7 +263,7 @@ INT MlmeThread(
* This is important in preemption kernels, which transfer the flow
* of execution immediately upon a complete().
*/
- DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__func__));
pObj->MLMEThr_pid = THREAD_PID_INIT_VALUE;
@@ -465,7 +465,7 @@ INT TimerQThread(
* This is important in preemption kernels, which transfer the flow
* of execution immediately upon a complete().
*/
- DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE,( "<---%s\n",__func__));
pObj->TimerQThr_pid = THREAD_PID_INIT_VALUE;
@@ -1258,7 +1258,7 @@ BOOLEAN RT28XXProbePostConfig(
if (!(pAd->BulkInEpAddr && pAd->BulkOutEpAddr[0]))
{
- printk("%s: Could not find both bulk-in and bulk-out endpoints\n", __FUNCTION__);
+ printk("%s: Could not find both bulk-in and bulk-out endpoints\n", __func__);
return FALSE;
}
diff --git a/drivers/staging/rt2870/common/2870_rtmp_init.c b/drivers/staging/rt2870/common/2870_rtmp_init.c
index 5d89a310d1ea..9f5143b3922e 100644
--- a/drivers/staging/rt2870/common/2870_rtmp_init.c
+++ b/drivers/staging/rt2870/common/2870_rtmp_init.c
@@ -1087,7 +1087,7 @@ PNDIS_PACKET GetPacketFromRxRing(
if (pRxWI->MPDUtotalByteCount > ThisFrameLen)
{
DBGPRINT(RT_DEBUG_ERROR, ("%s():pRxWIMPDUtotalByteCount(%d) large than RxDMALen(%ld)\n",
- __FUNCTION__, pRxWI->MPDUtotalByteCount, ThisFrameLen));
+ __func__, pRxWI->MPDUtotalByteCount, ThisFrameLen));
goto label_null;
}
#ifdef RT_BIG_ENDIAN
@@ -1098,7 +1098,7 @@ PNDIS_PACKET GetPacketFromRxRing(
pSkb = dev_alloc_skb(ThisFrameLen);
if (pSkb == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR,("%s():Cannot Allocate sk buffer for this Bulk-In buffer!\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR,("%s():Cannot Allocate sk buffer for this Bulk-In buffer!\n", __func__));
goto label_null;
}
diff --git a/drivers/staging/rt2870/common/ba_action.c b/drivers/staging/rt2870/common/ba_action.c
index 95addb20bced..d9f738177e2b 100644
--- a/drivers/staging/rt2870/common/ba_action.c
+++ b/drivers/staging/rt2870/common/ba_action.c
@@ -595,7 +595,7 @@ VOID BAOriSessionAdd(
pBAEntry->ORIBATimer.TimerValue = 0; //pFrame->TimeOutValue;
- DBGPRINT(RT_DEBUG_TRACE,("%s : TXBAbitmap = %x, BAWinSize = %d, TimeOut = %ld\n", __FUNCTION__, pEntry->TXBAbitmap,
+ DBGPRINT(RT_DEBUG_TRACE,("%s : TXBAbitmap = %x, BAWinSize = %d, TimeOut = %ld\n", __func__, pEntry->TXBAbitmap,
pBAEntry->BAWinSize, pBAEntry->ORIBATimer.TimerValue));
// SEND BAR ;
@@ -669,7 +669,7 @@ BOOLEAN BARecSessionAdd(
ba_refresh_reordering_mpdus(pAd, pBAEntry);
}
- DBGPRINT(RT_DEBUG_TRACE,("%s(%ld): Idx = %d, BAWinSize(req %d) = %d\n", __FUNCTION__, pAd->BATable.numAsRecipient, Idx,
+ DBGPRINT(RT_DEBUG_TRACE,("%s(%ld): Idx = %d, BAWinSize(req %d) = %d\n", __func__, pAd->BATable.numAsRecipient, Idx,
pFrame->BaParm.BufSize, BAWinSize));
// Start fill in parameters.
@@ -911,7 +911,7 @@ VOID BAOriSessionTearDown(
return;
}
- DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID));
+ DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __func__, Wcid, TID));
pBAEntry = &pAd->BATable.BAOriEntry[Idx];
DBGPRINT(RT_DEBUG_TRACE,("\t===>Idx = %ld, Wcid=%d.TID=%d, ORI_BA_Status = %d \n", Idx, Wcid, TID, pBAEntry->ORI_BA_Status));
@@ -970,7 +970,7 @@ VOID BARecSessionTearDown(
if (Idx == 0)
return;
- DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __FUNCTION__, Wcid, TID));
+ DBGPRINT(RT_DEBUG_TRACE,("%s===>Wcid=%d.TID=%d \n", __func__, Wcid, TID));
pBAEntry = &pAd->BATable.BARecEntry[Idx];
@@ -1181,7 +1181,7 @@ VOID PeerAddBAReqAction(
PULONG ptemp;
PMAC_TABLE_ENTRY pMacEntry;
- DBGPRINT(RT_DEBUG_TRACE, ("%s ==> (Wcid = %d)\n", __FUNCTION__, Elem->Wcid));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s ==> (Wcid = %d)\n", __func__, Elem->Wcid));
//hex_dump("AddBAReq", Elem->Msg, Elem->MsgLen);
@@ -1265,7 +1265,7 @@ VOID PeerAddBAReqAction(
MiniportMMRequest(pAd, QID_AC_BE, pOutBuffer, FrameLen);
MlmeFreeMemory(pAd, pOutBuffer);
- DBGPRINT(RT_DEBUG_TRACE, ("%s(%d): TID(%d), BufSize(%d) <== \n", __FUNCTION__, Elem->Wcid, ADDframe.BaParm.TID,
+ DBGPRINT(RT_DEBUG_TRACE, ("%s(%d): TID(%d), BufSize(%d) <== \n", __func__, Elem->Wcid, ADDframe.BaParm.TID,
ADDframe.BaParm.BufSize));
}
@@ -1284,7 +1284,7 @@ VOID PeerAddBARspAction(
if (Elem->Wcid >= MAX_LEN_OF_MAC_TABLE)
return;
- DBGPRINT(RT_DEBUG_TRACE, ("%s ==> Wcid(%d)\n", __FUNCTION__, Elem->Wcid));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s ==> Wcid(%d)\n", __func__, Elem->Wcid));
//hex_dump("PeerAddBARspAction()", Elem->Msg, Elem->MsgLen);
@@ -1325,7 +1325,7 @@ VOID PeerDelBAAction(
//PUCHAR pOutBuffer = NULL;
PFRAME_DELBA_REQ pDelFrame = NULL;
- DBGPRINT(RT_DEBUG_TRACE,("%s ==>\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE,("%s ==>\n", __func__));
//DELBA Request from unknown peer, ignore this.
if (PeerDelBAActionSanity(pAd, Elem->Wcid, Elem->Msg, Elem->MsgLen))
{
@@ -1362,7 +1362,7 @@ BOOLEAN CntlEnqueueForRecv(
TID = (UCHAR)pFrame->BARControl.TID;
- DBGPRINT(RT_DEBUG_TRACE, ("%s(): BAR-Wcid(%ld), Tid (%d)\n", __FUNCTION__, Wcid, TID));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s(): BAR-Wcid(%ld), Tid (%d)\n", __func__, Wcid, TID));
//hex_dump("BAR", (PCHAR) pFrame, MsgLen);
// Do nothing if the driver is starting halt state.
// This might happen when timer already been fired before cancel timer with mlmehalt
diff --git a/drivers/staging/rt2870/common/cmm_data.c b/drivers/staging/rt2870/common/cmm_data.c
index 4477a8e64a29..fd809abf6df0 100644
--- a/drivers/staging/rt2870/common/cmm_data.c
+++ b/drivers/staging/rt2870/common/cmm_data.c
@@ -2009,7 +2009,7 @@ BOOLEAN MacTableDeleteEntry(
}
else
{
- printk("\n%s: Impossible Wcid = %d !!!!!\n", __FUNCTION__, wcid);
+ printk("\n%s: Impossible Wcid = %d !!!!!\n", __func__, wcid);
}
}
diff --git a/drivers/staging/rt2870/common/cmm_info.c b/drivers/staging/rt2870/common/cmm_info.c
index 40792e162374..47a1b1a73f09 100644
--- a/drivers/staging/rt2870/common/cmm_info.c
+++ b/drivers/staging/rt2870/common/cmm_info.c
@@ -2331,7 +2331,7 @@ VOID RTMPIoctlGetMacTable(
wrq->u.data.length = sizeof(RT_802_11_MAC_TABLE);
if (copy_to_user(wrq->u.data.pointer, &MacTab, wrq->u.data.length))
{
- DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s: copy_to_user() fail\n", __func__));
}
msg = (CHAR *) kmalloc(sizeof(CHAR)*(MAX_LEN_OF_MAC_TABLE*MAC_LINE_LEN), MEM_ALLOC_FLAG);
diff --git a/drivers/staging/rt2870/common/dfs.c b/drivers/staging/rt2870/common/dfs.c
index 23cf1510e2d2..b09bba5cb206 100644
--- a/drivers/staging/rt2870/common/dfs.c
+++ b/drivers/staging/rt2870/common/dfs.c
@@ -428,7 +428,7 @@ INT Set_ChMovingTime_Proc(
pAd->CommonCfg.RadarDetect.ChMovingTime = Value;
- DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__,
+ DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __func__,
pAd->CommonCfg.RadarDetect.ChMovingTime));
return TRUE;
@@ -444,7 +444,7 @@ INT Set_LongPulseRadarTh_Proc(
pAd->CommonCfg.RadarDetect.LongPulseRadarTh = Value;
- DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __FUNCTION__,
+ DBGPRINT(RT_DEBUG_TRACE, ("%s:: %d\n", __func__,
pAd->CommonCfg.RadarDetect.LongPulseRadarTh));
return TRUE;
diff --git a/drivers/staging/rt2870/common/rtmp_init.c b/drivers/staging/rt2870/common/rtmp_init.c
index 87028fd60bc2..870a00da3dac 100644
--- a/drivers/staging/rt2870/common/rtmp_init.c
+++ b/drivers/staging/rt2870/common/rtmp_init.c
@@ -2746,7 +2746,7 @@ NDIS_STATUS NICLoadFirmware(
#ifdef BIN_IN_FILE
#define NICLF_DEFAULT_USE() \
flg_default_firm_use = TRUE; \
- printk("%s - Use default firmware!\n", __FUNCTION__);
+ printk("%s - Use default firmware!\n", __func__);
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PUCHAR src;
@@ -2761,7 +2761,7 @@ NDIS_STATUS NICLoadFirmware(
BOOLEAN flg_default_firm_use = FALSE;
- DBGPRINT(RT_DEBUG_TRACE, ("===> %s\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("===> %s\n", __func__));
/* init */
pFirmwareImage = NULL;
@@ -2784,7 +2784,7 @@ NDIS_STATUS NICLoadFirmware(
if (pFirmwareImage == NULL)
{
/* allocate fail, use default firmware array in firmware.h */
- printk("%s - Allocate memory fail!\n", __FUNCTION__);
+ printk("%s - Allocate memory fail!\n", __func__);
NICLF_DEFAULT_USE();
}
else
@@ -2805,7 +2805,7 @@ NDIS_STATUS NICLoadFirmware(
if (IS_ERR(srcf))
{
printk("%s - Error %ld opening %s\n",
- __FUNCTION__, -PTR_ERR(srcf), src);
+ __func__, -PTR_ERR(srcf), src);
NICLF_DEFAULT_USE();
break;
} /* End of if */
@@ -2813,7 +2813,7 @@ NDIS_STATUS NICLoadFirmware(
/* the object must have a read method */
if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL))
{
- printk("%s - %s does not have a write method\n", __FUNCTION__, src);
+ printk("%s - %s does not have a write method\n", __func__, src);
NICLF_DEFAULT_USE();
break;
} /* End of if */
@@ -2827,7 +2827,7 @@ NDIS_STATUS NICLoadFirmware(
if (FileLength != MAX_FIRMWARE_IMAGE_SIZE)
{
printk("%s: error file length (=%d) in RT2860AP.BIN\n",
- __FUNCTION__, FileLength);
+ __func__, FileLength);
NICLF_DEFAULT_USE();
break;
}
@@ -2850,7 +2850,7 @@ NDIS_STATUS NICLoadFirmware(
/* CRC fail */
printk("%s: CRC = 0x%02x 0x%02x "
"error, should be 0x%02x 0x%02x\n",
- __FUNCTION__,
+ __func__,
pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-2],
pFirmwareImage[MAX_FIRMWARE_IMAGE_SIZE-1],
(UCHAR)(crc>>8), (UCHAR)(crc));
@@ -2869,7 +2869,7 @@ NDIS_STATUS NICLoadFirmware(
((FIRMWARE_MAJOR_VERSION << 8) +
FIRMWARE_MINOR_VERSION))
{
- printk("%s: firmware version too old!\n", __FUNCTION__);
+ printk("%s: firmware version too old!\n", __func__);
NICLF_DEFAULT_USE();
break;
} /* End of if */
@@ -3024,10 +3024,10 @@ NDIS_STATUS NICLoadFirmware(
#if 0
DBGPRINT(RT_DEBUG_TRACE,
- ("<=== %s (src=%s, status=%d)\n", __FUNCTION__, src, Status));
+ ("<=== %s (src=%s, status=%d)\n", __func__, src, Status));
#else
DBGPRINT(RT_DEBUG_TRACE,
- ("<=== %s (status=%d)\n", __FUNCTION__, Status));
+ ("<=== %s (status=%d)\n", __func__, Status));
#endif
return Status;
} /* End of NICLoadFirmware */
diff --git a/drivers/staging/rt2870/common/rtusb_bulk.c b/drivers/staging/rt2870/common/rtusb_bulk.c
index 3c6ba1b9deb1..c46d9166ccf4 100644
--- a/drivers/staging/rt2870/common/rtusb_bulk.c
+++ b/drivers/staging/rt2870/common/rtusb_bulk.c
@@ -329,7 +329,7 @@ VOID RTUSBBulkOutDataPacket(
if (pTxInfo->QSEL != FIFO_EDCA)
{
- printk("%s(): ====> pTxInfo->QueueSel(%d)!= FIFO_EDCA!!!!\n", __FUNCTION__, pTxInfo->QSEL);
+ printk("%s(): ====> pTxInfo->QueueSel(%d)!= FIFO_EDCA!!!!\n", __func__, pTxInfo->QSEL);
printk("\tCWPos=%ld, NBPos=%ld, ENBPos=%ld, bCopy=%d!\n", pHTTXContext->CurWritePosition, pHTTXContext->NextBulkOutPosition, pHTTXContext->ENextBulkOutPosition, pHTTXContext->bCopySavePad);
hex_dump("Wrong QSel Pkt:", (PUCHAR)&pWirelessPkt[TmpBulkEndPos], (pHTTXContext->CurWritePosition - pHTTXContext->NextBulkOutPosition));
}
@@ -942,7 +942,7 @@ VOID RTUSBBulkOutMLMEPacket(
pTxInfo = (PTXINFO_STRUC)pMLMEContext->TransferBuffer;
if (pTxInfo->QSEL != FIFO_EDCA)
{
- printk("%s(): ====> pTxInfo->QueueSel(%d)!= FIFO_EDCA!!!!\n", __FUNCTION__, pTxInfo->QSEL);
+ printk("%s(): ====> pTxInfo->QueueSel(%d)!= FIFO_EDCA!!!!\n", __func__, pTxInfo->QSEL);
printk("\tMLME_Index=%d!\n", Index);
hex_dump("Wrong QSel Pkt:", (PUCHAR)pMLMEContext->TransferBuffer, pTxInfo->USBDMATxPktLen);
}
diff --git a/drivers/staging/rt2870/common/spectrum.c b/drivers/staging/rt2870/common/spectrum.c
index abba8405184f..43782ce9288f 100644
--- a/drivers/staging/rt2870/common/spectrum.c
+++ b/drivers/staging/rt2870/common/spectrum.c
@@ -48,7 +48,7 @@ VOID MeasureReqTabInit(
if (pAd->CommonCfg.pMeasureReqTab)
NdisZeroMemory(pAd->CommonCfg.pMeasureReqTab, sizeof(MEASURE_REQ_TAB));
else
- DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pMeasureReqTab.\n", __func__));
return;
}
@@ -76,7 +76,7 @@ static PMEASURE_REQ_ENTRY MeasureReqLookUp(
if (pTab == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__));
return NULL;
}
@@ -113,7 +113,7 @@ static PMEASURE_REQ_ENTRY MeasureReqInsert(
if(pTab == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__));
return NULL;
}
@@ -174,7 +174,7 @@ static PMEASURE_REQ_ENTRY MeasureReqInsert(
else
{
pEntry = NULL;
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab tab full.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab tab full.\n", __func__));
}
// add this Neighbor entry into HASH table
@@ -209,7 +209,7 @@ static VOID MeasureReqDelete(
if(pTab == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pMeasureReqTab doesn't exist.\n", __func__));
return;
}
@@ -266,7 +266,7 @@ VOID TpcReqTabInit(
if (pAd->CommonCfg.pTpcReqTab)
NdisZeroMemory(pAd->CommonCfg.pTpcReqTab, sizeof(TPC_REQ_TAB));
else
- DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s Fail to alloc memory for pAd->CommonCfg.pTpcReqTab.\n", __func__));
return;
}
@@ -294,7 +294,7 @@ static PTPC_REQ_ENTRY TpcReqLookUp(
if (pTab == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__));
return NULL;
}
@@ -332,7 +332,7 @@ static PTPC_REQ_ENTRY TpcReqInsert(
if(pTab == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__));
return NULL;
}
@@ -393,7 +393,7 @@ static PTPC_REQ_ENTRY TpcReqInsert(
else
{
pEntry = NULL;
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab tab full.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab tab full.\n", __func__));
}
// add this Neighbor entry into HASH table
@@ -428,7 +428,7 @@ static VOID TpcReqDelete(
if(pTab == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: pTpcReqTab doesn't exist.\n", __func__));
return;
}
@@ -781,7 +781,7 @@ VOID EnqueueMeasurementReq(
NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory
if(NStatus != NDIS_STATUS_SUCCESS)
{
- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
return;
}
NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
@@ -843,7 +843,7 @@ VOID EnqueueMeasurementRep(
NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory
if(NStatus != NDIS_STATUS_SUCCESS)
{
- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
return;
}
NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
@@ -897,7 +897,7 @@ VOID EnqueueTPCReq(
NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory
if(NStatus != NDIS_STATUS_SUCCESS)
{
- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
return;
}
NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
@@ -949,7 +949,7 @@ VOID EnqueueTPCRep(
NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory
if(NStatus != NDIS_STATUS_SUCCESS)
{
- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
return;
}
NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
@@ -1002,7 +1002,7 @@ VOID EnqueueChSwAnn(
NStatus = MlmeAllocateMemory(pAd, (PVOID)&pOutBuffer); //Get an unused nonpaged memory
if(NStatus != NDIS_STATUS_SUCCESS)
{
- DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s() allocate memory failed \n", __func__));
return;
}
NdisMoveMemory(pOutBuffer, (PCHAR)&ActHdr, sizeof(HEADER_802_11));
@@ -1595,7 +1595,7 @@ static VOID PeerMeasureReportAction(
if ((pMeasureReportInfo = kmalloc(sizeof(MEASURE_RPI_REPORT), GFP_ATOMIC)) == NULL)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%d).\n", __FUNCTION__, sizeof(MEASURE_RPI_REPORT)));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s unable to alloc memory for measure report buffer (size=%d).\n", __func__, sizeof(MEASURE_RPI_REPORT)));
return;
}
@@ -1704,7 +1704,7 @@ static VOID PeerTpcRepAction(
{
TpcReqDelete(pAd, pEntry->DialogToken);
DBGPRINT(RT_DEBUG_TRACE, ("%s: DialogToken=%x, TxPwr=%d, LinkMargin=%d\n",
- __FUNCTION__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin));
+ __func__, DialogToken, TpcRepInfo.TxPwr, TpcRepInfo.LinkMargin));
}
}
@@ -1820,7 +1820,7 @@ INT Set_MeasureReq_Proc(
MeasureReqType = simple_strtol(thisChar, 0, 16);
if (MeasureReqType > 3)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __FUNCTION__, MeasureReqType));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow MeasureReqType(%d)\n", __func__, MeasureReqType));
return TRUE;
}
break;
@@ -1832,10 +1832,10 @@ INT Set_MeasureReq_Proc(
ArgIdx++;
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __FUNCTION__, Aid, MeasureReqType, MeasureCh));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d, MeasureReqType=%d MeasureCh=%d\n", __func__, Aid, MeasureReqType, MeasureCh));
if (!VALID_WCID(Aid))
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, Aid));
return TRUE;
}
@@ -1860,10 +1860,10 @@ INT Set_TpcReq_Proc(
Aid = simple_strtol(arg, 0, 16);
- DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __FUNCTION__, Aid));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::Aid = %d\n", __func__, Aid));
if (!VALID_WCID(Aid))
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __FUNCTION__, Aid));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: unknow sta of Aid(%d)\n", __func__, Aid));
return TRUE;
}
diff --git a/drivers/staging/rt2870/rt_ate.c b/drivers/staging/rt2870/rt_ate.c
index e99b3da0b62d..27c763ee9276 100644
--- a/drivers/staging/rt2870/rt_ate.c
+++ b/drivers/staging/rt2870/rt_ate.c
@@ -314,7 +314,7 @@ static INT ATETxPwrHandler(
Bbp94 = BBPR94_DEFAULT;
}
- ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94));
+ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%ld, BBP_R94=%d)\n", __func__, TxPower, R, Bbp94));
}
else// 5.5 GHz
{
@@ -341,7 +341,7 @@ static INT ATETxPwrHandler(
R = (ULONG) TxPower;
}
- ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%lu)\n", __FUNCTION__, TxPower, R));
+ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R=%lu)\n", __func__, TxPower, R));
}
if (pAd->ate.Channel <= 14)
@@ -454,7 +454,7 @@ static INT ATETxPwrHandler(
Bbp94 = BBPR94_DEFAULT;
}
- ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R3=%ld, BBP_R94=%d)\n", __FUNCTION__, TxPower, R, Bbp94));
+ ATEDBGPRINT(RT_DEBUG_TRACE, ("%s (TxPower=%d, R3=%ld, BBP_R94=%d)\n", __func__, TxPower, R, Bbp94));
if (pAd->ate.Channel <= 14)
{
@@ -2261,7 +2261,7 @@ INT Set_ATE_Load_E2P_Proc(
UINT32 FileLength = 0;
UINT32 value = simple_strtol(arg, 0, 10);
- ATEDBGPRINT(RT_DEBUG_ERROR, ("===> %s (value=%d)\n\n", __FUNCTION__, value));
+ ATEDBGPRINT(RT_DEBUG_ERROR, ("===> %s (value=%d)\n\n", __func__, value));
if (value > 0)
{
@@ -2285,14 +2285,14 @@ INT Set_ATE_Load_E2P_Proc(
if (IS_ERR(srcf))
{
- ate_print("%s - Error %ld opening %s\n", __FUNCTION__, -PTR_ERR(srcf), src);
+ ate_print("%s - Error %ld opening %s\n", __func__, -PTR_ERR(srcf), src);
break;
}
/* the object must have a read method */
if ((srcf->f_op == NULL) || (srcf->f_op->read == NULL))
{
- ate_print("%s - %s does not have a read method\n", __FUNCTION__, src);
+ ate_print("%s - %s does not have a read method\n", __func__, src);
break;
}
@@ -2305,7 +2305,7 @@ INT Set_ATE_Load_E2P_Proc(
if (FileLength != EEPROM_SIZE)
{
ate_print("%s: error file length (=%d) in e2p.bin\n",
- __FUNCTION__, FileLength);
+ __func__, FileLength);
break;
}
else
@@ -2337,7 +2337,7 @@ INT Set_ATE_Load_E2P_Proc(
current->fsuid = orgfsuid;
current->fsgid = orgfsgid;
}
- ATEDBGPRINT(RT_DEBUG_ERROR, ("<=== %s (ret=%d)\n", __FUNCTION__, ret));
+ ATEDBGPRINT(RT_DEBUG_ERROR, ("<=== %s (ret=%d)\n", __func__, ret));
return ret;
@@ -2350,12 +2350,12 @@ INT Set_ATE_Load_E2P_Proc(
USHORT WriteEEPROM[(EEPROM_SIZE/2)];
struct iwreq *wrq = (struct iwreq *)arg;
- ATEDBGPRINT(RT_DEBUG_TRACE, ("===> %s (wrq->u.data.length = %d)\n\n", __FUNCTION__, wrq->u.data.length));
+ ATEDBGPRINT(RT_DEBUG_TRACE, ("===> %s (wrq->u.data.length = %d)\n\n", __func__, wrq->u.data.length));
if (wrq->u.data.length != EEPROM_SIZE)
{
ate_print("%s: error length (=%d) from host\n",
- __FUNCTION__, wrq->u.data.length);
+ __func__, wrq->u.data.length);
return FALSE;
}
else/* (wrq->u.data.length == EEPROM_SIZE) */
@@ -2374,7 +2374,7 @@ INT Set_ATE_Load_E2P_Proc(
} while(FALSE);
}
- ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== %s\n", __FUNCTION__));
+ ATEDBGPRINT(RT_DEBUG_TRACE, ("<=== %s\n", __func__));
return TRUE;
@@ -4083,7 +4083,7 @@ VOID RtmpDoAte(
Command_Id = ntohs(pRaCfg->command_id);
- ATEDBGPRINT(RT_DEBUG_TRACE,("\n%s: Command_Id = 0x%04x !\n", __FUNCTION__, Command_Id));
+ ATEDBGPRINT(RT_DEBUG_TRACE,("\n%s: Command_Id = 0x%04x !\n", __func__, Command_Id));
switch (Command_Id)
{
@@ -6117,7 +6117,7 @@ BOOLEAN SyncTxRxConfig(PRTMP_ADAPTER pAd, USHORT offset, UCHAR value)
pAd->ate.TxAntennaSel = 2;
break;
default:
- DBGPRINT(RT_DEBUG_TRACE, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s -- Sth. wrong! : return FALSE; \n", __func__));
return FALSE;
}
break;/* case BBP_R1 */
@@ -6155,13 +6155,13 @@ BOOLEAN SyncTxRxConfig(PRTMP_ADAPTER pAd, USHORT offset, UCHAR value)
pAd->ate.RxAntennaSel = 3;
break;
default:
- DBGPRINT(RT_DEBUG_ERROR, ("%s -- Impossible! : return FALSE; \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s -- Impossible! : return FALSE; \n", __func__));
return FALSE;
}
break;/* case BBP_R3 */
default:
- DBGPRINT(RT_DEBUG_ERROR, ("%s -- Sth. wrong! : return FALSE; \n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s -- Sth. wrong! : return FALSE; \n", __func__));
return FALSE;
}
diff --git a/drivers/staging/rt2870/rt_linux.c b/drivers/staging/rt2870/rt_linux.c
index f2ea8ebcd042..992e3d16f9b4 100644
--- a/drivers/staging/rt2870/rt_linux.c
+++ b/drivers/staging/rt2870/rt_linux.c
@@ -404,7 +404,7 @@ NDIS_STATUS RTMPAllocateNdisPacket(
skb_put(GET_OS_PKT_TYPE(pPacket), HeaderLen+DataLen);
RTMP_SET_PACKET_SOURCE(pPacket, PKTSRC_NDIS);
-// printk("%s : pPacket = %p, len = %d\n", __FUNCTION__, pPacket, GET_OS_PKT_LEN(pPacket));
+// printk("%s : pPacket = %p, len = %d\n", __func__, pPacket, GET_OS_PKT_LEN(pPacket));
*ppPacket = pPacket;
return NDIS_STATUS_SUCCESS;
}
@@ -814,13 +814,13 @@ VOID RTMPSendWirelessEvent(
if (event_table_len == 0)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s : The type(%0x02x) is not valid.\n", __FUNCTION__, type));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : The type(%0x02x) is not valid.\n", __func__, type));
return;
}
if (event >= event_table_len)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s : The event(%0x02x) is not valid.\n", __FUNCTION__, event));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : The event(%0x02x) is not valid.\n", __func__, event));
return;
}
@@ -858,14 +858,14 @@ VOID RTMPSendWirelessEvent(
//send wireless event
wireless_send_event(pAd->net_dev, IWEVCUSTOM, &wrqu, pBuf);
- //DBGPRINT(RT_DEBUG_TRACE, ("%s : %s\n", __FUNCTION__, pBuf));
+ //DBGPRINT(RT_DEBUG_TRACE, ("%s : %s\n", __func__, pBuf));
kfree(pBuf);
}
else
- DBGPRINT(RT_DEBUG_ERROR, ("%s : Can't allocate memory for wireless event.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : Can't allocate memory for wireless event.\n", __func__));
#else
- DBGPRINT(RT_DEBUG_ERROR, ("%s : The Wireless Extension MUST be v15 or newer.\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : The Wireless Extension MUST be v15 or newer.\n", __func__));
#endif /* WIRELESS_EXT >= 15 */
}
@@ -889,13 +889,13 @@ void send_monitor_packets(
ASSERT(pRxBlk->pRxPacket);
if (pRxBlk->DataSize < 10)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too small! (%d)\n", __FUNCTION__, pRxBlk->DataSize));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too small! (%d)\n", __func__, pRxBlk->DataSize));
goto err_free_sk_buff;
}
if (pRxBlk->DataSize + sizeof(wlan_ng_prism2_header) > RX_BUFFER_AGGRESIZE)
{
- DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%d)\n", __FUNCTION__, pRxBlk->DataSize + sizeof(wlan_ng_prism2_header)));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : Size is too large! (%d)\n", __func__, pRxBlk->DataSize + sizeof(wlan_ng_prism2_header)));
goto err_free_sk_buff;
}
@@ -951,7 +951,7 @@ void send_monitor_packets(
if (skb_headroom(pOSPkt) < (sizeof(wlan_ng_prism2_header)+ header_len)) {
if (pskb_expand_head(pOSPkt, (sizeof(wlan_ng_prism2_header) + header_len), 0, GFP_ATOMIC)) {
- DBGPRINT(RT_DEBUG_ERROR, ("%s : Reallocate header size of sk_buff fail!\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s : Reallocate header size of sk_buff fail!\n", __func__));
goto err_free_sk_buff;
} //end if
} //end if
diff --git a/drivers/staging/rt2870/rt_linux.h b/drivers/staging/rt2870/rt_linux.h
index 814297577261..859f9cef0a19 100644
--- a/drivers/staging/rt2870/rt_linux.h
+++ b/drivers/staging/rt2870/rt_linux.h
@@ -124,7 +124,7 @@ typedef int (*HARD_START_XMIT_FUNC)(struct sk_buff *skb, struct net_device *net_
#define RT_MOD_INC_USE_COUNT() \
if (!try_module_get(THIS_MODULE)) \
{ \
- DBGPRINT(RT_DEBUG_ERROR, ("%s: cannot reserve module\n", __FUNCTION__)); \
+ DBGPRINT(RT_DEBUG_ERROR, ("%s: cannot reserve module\n", __func__)); \
return -1; \
}
diff --git a/drivers/staging/rt2870/rt_main_dev.c b/drivers/staging/rt2870/rt_main_dev.c
index b990f8a61641..313ecea0bfa8 100644
--- a/drivers/staging/rt2870/rt_main_dev.c
+++ b/drivers/staging/rt2870/rt_main_dev.c
@@ -1554,7 +1554,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb)
#if 0
// if ((pkt->data[0] & 0x1) == 0)
{
- //hex_dump(__FUNCTION__, pkt->data, pkt->len);
+ //hex_dump(__func__, pkt->data, pkt->len);
printk("pPacket = %x\n", pPacket);
}
#endif
diff --git a/drivers/staging/rt2870/rt_profile.c b/drivers/staging/rt2870/rt_profile.c
index c4474a6428ac..467fea35e4a9 100644
--- a/drivers/staging/rt2870/rt_profile.c
+++ b/drivers/staging/rt2870/rt_profile.c
@@ -1024,7 +1024,7 @@ NDIS_STATUS RTMPReadParametersHook(
pAd->MlmeAux.SsidLen = pAd->CommonCfg.SsidLen;
NdisZeroMemory(pAd->MlmeAux.Ssid, NDIS_802_11_LENGTH_SSID);
NdisMoveMemory(pAd->MlmeAux.Ssid, tmpbuf, pAd->MlmeAux.SsidLen);
- DBGPRINT(RT_DEBUG_TRACE, ("%s::(SSID=%s)\n", __FUNCTION__, tmpbuf));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::(SSID=%s)\n", __func__, tmpbuf));
}
}
}
@@ -1043,7 +1043,7 @@ NDIS_STATUS RTMPReadParametersHook(
pAd->StaCfg.BssType = BSS_INFRA;
// Reset Ralink supplicant to not use, it will be set to start when UI set PMK key
pAd->StaCfg.WpaState = SS_NOTUSE;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::(NetworkType=%d)\n", __FUNCTION__, pAd->StaCfg.BssType));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::(NetworkType=%d)\n", __func__, pAd->StaCfg.BssType));
}
}
#endif // CONFIG_STA_SUPPORT //
@@ -1341,7 +1341,7 @@ NDIS_STATUS RTMPReadParametersHook(
pAd->StaCfg.PortSecured = WPA_802_1X_PORT_NOT_SECURED;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __func__, pAd->StaCfg.WepStatus));
}
#endif // CONFIG_STA_SUPPORT //
}
@@ -1368,7 +1368,7 @@ NDIS_STATUS RTMPReadParametersHook(
pAd->StaCfg.bMixCipher = FALSE;
//RTMPMakeRSNIE(pAd, pAd->StaCfg.AuthMode, pAd->StaCfg.WepStatus, 0);
- DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __FUNCTION__, pAd->StaCfg.WepStatus));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::(EncrypType=%d)\n", __func__, pAd->StaCfg.WepStatus));
}
#endif // CONFIG_STA_SUPPORT //
}
@@ -1405,7 +1405,7 @@ NDIS_STATUS RTMPReadParametersHook(
else
{
err = 1;
- DBGPRINT(RT_DEBUG_ERROR, ("%s::(WPAPSK key-string required 8 ~ 64 characters!)\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_ERROR, ("%s::(WPAPSK key-string required 8 ~ 64 characters!)\n", __func__));
}
if (err == 0)
@@ -1436,7 +1436,7 @@ NDIS_STATUS RTMPReadParametersHook(
pAd->StaCfg.WpaState = SS_NOTUSE;
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::(WPAPSK=%s)\n", __FUNCTION__, tmpbuf));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::(WPAPSK=%s)\n", __func__, tmpbuf));
}
}
}
diff --git a/drivers/staging/rt2870/rtmp_def.h b/drivers/staging/rt2870/rtmp_def.h
index 9b86325b4c55..c0f7561a9d9d 100644
--- a/drivers/staging/rt2870/rtmp_def.h
+++ b/drivers/staging/rt2870/rtmp_def.h
@@ -342,7 +342,7 @@
/* sanity check for apidx */
#define MBSS_MR_APIDX_SANITY_CHECK(apidx) \
{ if (apidx > MAX_MBSSID_NUM) { \
- printk("%s> Error! apidx = %d > MAX_MBSSID_NUM!\n", __FUNCTION__, apidx); \
+ printk("%s> Error! apidx = %d > MAX_MBSSID_NUM!\n", __func__, apidx); \
apidx = MAIN_MBSSID; } }
#define VALID_WCID(_wcid) ((_wcid) > 0 && (_wcid) < MAX_LEN_OF_MAC_TABLE )
diff --git a/drivers/staging/rt2870/sta_ioctl.c b/drivers/staging/rt2870/sta_ioctl.c
index 422f39f9004a..91f0fab11313 100644
--- a/drivers/staging/rt2870/sta_ioctl.c
+++ b/drivers/staging/rt2870/sta_ioctl.c
@@ -2224,7 +2224,7 @@ rt_private_show(struct net_device *dev, struct iw_request_info *info,
wrq->length = strlen(extra) + 1; // 1: size of '\0'
break;
default:
- DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __FUNCTION__, subcmd));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __func__, subcmd));
break;
}
@@ -2243,7 +2243,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
MLME_DISASSOC_REQ_STRUCT DisAssocReq;
MLME_DEAUTH_REQ_STRUCT DeAuthReq;
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __func__));
if (pMlme == NULL)
return -EINVAL;
@@ -2252,7 +2252,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
{
#ifdef IW_MLME_DEAUTH
case IW_MLME_DEAUTH:
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __func__));
COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid);
DeAuthReq.Reason = pMlme->reason_code;
MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT);
@@ -2267,7 +2267,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
#endif // IW_MLME_DEAUTH //
#ifdef IW_MLME_DISASSOC
case IW_MLME_DISASSOC:
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __func__));
COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid);
DisAssocReq.Reason = pMlme->reason_code;
@@ -2281,7 +2281,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
break;
#endif // IW_MLME_DISASSOC //
default:
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __func__));
break;
}
@@ -2314,7 +2314,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
else if (param->value == IW_AUTH_WPA_VERSION_WPA2)
pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_CIPHER_PAIRWISE:
if (param->value == IW_AUTH_CIPHER_NONE)
@@ -2345,7 +2345,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus;
pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled;
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_CIPHER_GROUP:
if (param->value == IW_AUTH_CIPHER_NONE)
@@ -2365,7 +2365,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
{
pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled;
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_KEY_MGMT:
if (param->value == IW_AUTH_KEY_MGMT_802_1X)
@@ -2395,7 +2395,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
//pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED;
STA_PORT_SECURED(pAdapter);
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
break;
@@ -2408,7 +2408,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled;
pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled;
}*/
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_DROP_UNENCRYPTED:
if (param->value != 0)
@@ -2418,7 +2418,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
//pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED;
STA_PORT_SECURED(pAdapter);
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_80211_AUTH_ALG:
if (param->value & IW_AUTH_ALG_SHARED_KEY)
@@ -2431,10 +2431,10 @@ int rt_ioctl_siwauth(struct net_device *dev,
}
else
return -EINVAL;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_WPA_ENABLED:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __func__, param->value));
break;
default:
return -EOPNOTSUPP;
@@ -2542,7 +2542,7 @@ int rt_ioctl_siwencodeext(struct net_device *dev,
pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE;
AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx);
NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY));
- DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __FUNCTION__, encoding->flags));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __func__, encoding->flags));
}
else
{
@@ -2554,15 +2554,15 @@ int rt_ioctl_siwencodeext(struct net_device *dev,
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
{
pAdapter->StaCfg.DefaultKeyId = keyIdx;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __FUNCTION__, pAdapter->StaCfg.DefaultKeyId));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __func__, pAdapter->StaCfg.DefaultKeyId));
}
switch (alg) {
case IW_ENCODE_ALG_NONE:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __func__));
break;
case IW_ENCODE_ALG_WEP:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __FUNCTION__, ext->key_len, keyIdx));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __func__, ext->key_len, keyIdx));
if (ext->key_len == MAX_WEP_KEY_SIZE)
{
pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE;
@@ -2595,7 +2595,7 @@ int rt_ioctl_siwencodeext(struct net_device *dev,
}
break;
case IW_ENCODE_ALG_TKIP:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __FUNCTION__, keyIdx, ext->key_len));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __func__, keyIdx, ext->key_len));
if (ext->key_len == 32)
{
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
diff --git a/drivers/staging/rt2870/tmp60 b/drivers/staging/rt2870/tmp60
index 992096a248c5..975e44484379 100644
--- a/drivers/staging/rt2870/tmp60
+++ b/drivers/staging/rt2870/tmp60
@@ -2224,7 +2224,7 @@ rt_private_show(struct net_device *dev, struct iw_request_info *info,
wrq->length = strlen(extra) + 1; // 1: size of '\0'
break;
default:
- DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __FUNCTION__, subcmd));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __func__, subcmd));
break;
}
@@ -2243,7 +2243,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
MLME_DISASSOC_REQ_STRUCT DisAssocReq;
MLME_DEAUTH_REQ_STRUCT DeAuthReq;
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __func__));
if (pMlme == NULL)
return -EINVAL;
@@ -2252,7 +2252,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
{
#ifdef IW_MLME_DEAUTH
case IW_MLME_DEAUTH:
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __func__));
COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid);
DeAuthReq.Reason = pMlme->reason_code;
MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT);
@@ -2267,7 +2267,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
#endif // IW_MLME_DEAUTH //
#ifdef IW_MLME_DISASSOC
case IW_MLME_DISASSOC:
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __func__));
COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid);
DisAssocReq.Reason = pMlme->reason_code;
@@ -2281,7 +2281,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
break;
#endif // IW_MLME_DISASSOC //
default:
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __func__));
break;
}
@@ -2314,7 +2314,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
else if (param->value == IW_AUTH_WPA_VERSION_WPA2)
pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_CIPHER_PAIRWISE:
if (param->value == IW_AUTH_CIPHER_NONE)
@@ -2345,7 +2345,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus;
pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled;
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_CIPHER_GROUP:
if (param->value == IW_AUTH_CIPHER_NONE)
@@ -2365,7 +2365,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
{
pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled;
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_KEY_MGMT:
if (param->value == IW_AUTH_KEY_MGMT_802_1X)
@@ -2395,7 +2395,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
//pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED;
STA_PORT_SECURED(pAdapter);
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
break;
@@ -2408,7 +2408,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled;
pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled;
}*/
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_DROP_UNENCRYPTED:
if (param->value != 0)
@@ -2418,7 +2418,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
//pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED;
STA_PORT_SECURED(pAdapter);
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_80211_AUTH_ALG:
if (param->value & IW_AUTH_ALG_SHARED_KEY)
@@ -2431,10 +2431,10 @@ int rt_ioctl_siwauth(struct net_device *dev,
}
else
return -EINVAL;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_WPA_ENABLED:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __func__, param->value));
break;
default:
return -EOPNOTSUPP;
@@ -2542,7 +2542,7 @@ int rt_ioctl_siwencodeext(struct net_device *dev,
pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE;
AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx);
NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY));
- DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __FUNCTION__, encoding->flags));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __func__, encoding->flags));
}
else
{
@@ -2554,15 +2554,15 @@ int rt_ioctl_siwencodeext(struct net_device *dev,
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
{
pAdapter->StaCfg.DefaultKeyId = keyIdx;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __FUNCTION__, pAdapter->StaCfg.DefaultKeyId));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __func__, pAdapter->StaCfg.DefaultKeyId));
}
switch (alg) {
case IW_ENCODE_ALG_NONE:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __func__));
break;
case IW_ENCODE_ALG_WEP:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __FUNCTION__, ext->key_len, keyIdx));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __func__, ext->key_len, keyIdx));
if (ext->key_len == MAX_WEP_KEY_SIZE)
{
pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE;
@@ -2580,7 +2580,7 @@ int rt_ioctl_siwencodeext(struct net_device *dev,
NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len);
break;
case IW_ENCODE_ALG_TKIP:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __FUNCTION__, keyIdx, ext->key_len));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __func__, keyIdx, ext->key_len));
if (ext->key_len == 32)
{
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
diff --git a/drivers/staging/rt2870/tmp61 b/drivers/staging/rt2870/tmp61
index 992096a248c5..975e44484379 100644
--- a/drivers/staging/rt2870/tmp61
+++ b/drivers/staging/rt2870/tmp61
@@ -2224,7 +2224,7 @@ rt_private_show(struct net_device *dev, struct iw_request_info *info,
wrq->length = strlen(extra) + 1; // 1: size of '\0'
break;
default:
- DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __FUNCTION__, subcmd));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s - unknow subcmd = %d\n", __func__, subcmd));
break;
}
@@ -2243,7 +2243,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
MLME_DISASSOC_REQ_STRUCT DisAssocReq;
MLME_DEAUTH_REQ_STRUCT DeAuthReq;
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s\n", __func__));
if (pMlme == NULL)
return -EINVAL;
@@ -2252,7 +2252,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
{
#ifdef IW_MLME_DEAUTH
case IW_MLME_DEAUTH:
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DEAUTH\n", __func__));
COPY_MAC_ADDR(DeAuthReq.Addr, pAd->CommonCfg.Bssid);
DeAuthReq.Reason = pMlme->reason_code;
MsgElem.MsgLen = sizeof(MLME_DEAUTH_REQ_STRUCT);
@@ -2267,7 +2267,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
#endif // IW_MLME_DEAUTH //
#ifdef IW_MLME_DISASSOC
case IW_MLME_DISASSOC:
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - IW_MLME_DISASSOC\n", __func__));
COPY_MAC_ADDR(DisAssocReq.Addr, pAd->CommonCfg.Bssid);
DisAssocReq.Reason = pMlme->reason_code;
@@ -2281,7 +2281,7 @@ int rt_ioctl_siwmlme(struct net_device *dev,
break;
#endif // IW_MLME_DISASSOC //
default:
- DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("====> %s - Unknow Command\n", __func__));
break;
}
@@ -2314,7 +2314,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
else if (param->value == IW_AUTH_WPA_VERSION_WPA2)
pAdapter->StaCfg.AuthMode = Ndis802_11AuthModeWPA2PSK;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_CIPHER_PAIRWISE:
if (param->value == IW_AUTH_CIPHER_NONE)
@@ -2345,7 +2345,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
pAdapter->StaCfg.OrigWepStatus = pAdapter->StaCfg.WepStatus;
pAdapter->StaCfg.PairCipher = Ndis802_11Encryption3Enabled;
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_PAIRWISE - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_CIPHER_GROUP:
if (param->value == IW_AUTH_CIPHER_NONE)
@@ -2365,7 +2365,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
{
pAdapter->StaCfg.GroupCipher = Ndis802_11Encryption3Enabled;
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_CIPHER_GROUP - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_KEY_MGMT:
if (param->value == IW_AUTH_KEY_MGMT_802_1X)
@@ -2395,7 +2395,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
//pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED;
STA_PORT_SECURED(pAdapter);
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_KEY_MGMT - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
break;
@@ -2408,7 +2408,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
pAdapter->StaCfg.PairCipher = Ndis802_11WEPDisabled;
pAdapter->StaCfg.GroupCipher = Ndis802_11WEPDisabled;
}*/
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_PRIVACY_INVOKED - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_DROP_UNENCRYPTED:
if (param->value != 0)
@@ -2418,7 +2418,7 @@ int rt_ioctl_siwauth(struct net_device *dev,
//pAdapter->StaCfg.PortSecured = WPA_802_1X_PORT_SECURED;
STA_PORT_SECURED(pAdapter);
}
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_VERSION - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_80211_AUTH_ALG:
if (param->value & IW_AUTH_ALG_SHARED_KEY)
@@ -2431,10 +2431,10 @@ int rt_ioctl_siwauth(struct net_device *dev,
}
else
return -EINVAL;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_80211_AUTH_ALG - param->value = %d!\n", __func__, param->value));
break;
case IW_AUTH_WPA_ENABLED:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __FUNCTION__, param->value));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_AUTH_WPA_ENABLED - Driver supports WPA!(param->value = %d)\n", __func__, param->value));
break;
default:
return -EOPNOTSUPP;
@@ -2542,7 +2542,7 @@ int rt_ioctl_siwencodeext(struct net_device *dev,
pAdapter->SharedKey[BSS0][keyIdx].CipherAlg = CIPHER_NONE;
AsicRemoveSharedKeyEntry(pAdapter, 0, (UCHAR)keyIdx);
NdisZeroMemory(&pAdapter->SharedKey[BSS0][keyIdx], sizeof(CIPHER_KEY));
- DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __FUNCTION__, encoding->flags));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::Remove all keys!(encoding->flags = %x)\n", __func__, encoding->flags));
}
else
{
@@ -2554,15 +2554,15 @@ int rt_ioctl_siwencodeext(struct net_device *dev,
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
{
pAdapter->StaCfg.DefaultKeyId = keyIdx;
- DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __FUNCTION__, pAdapter->StaCfg.DefaultKeyId));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::DefaultKeyId = %d\n", __func__, pAdapter->StaCfg.DefaultKeyId));
}
switch (alg) {
case IW_ENCODE_ALG_NONE:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __FUNCTION__));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_NONE\n", __func__));
break;
case IW_ENCODE_ALG_WEP:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __FUNCTION__, ext->key_len, keyIdx));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_WEP - ext->key_len = %d, keyIdx = %d\n", __func__, ext->key_len, keyIdx));
if (ext->key_len == MAX_WEP_KEY_SIZE)
{
pAdapter->SharedKey[BSS0][keyIdx].KeyLen = MAX_WEP_KEY_SIZE;
@@ -2580,7 +2580,7 @@ int rt_ioctl_siwencodeext(struct net_device *dev,
NdisMoveMemory(pAdapter->SharedKey[BSS0][keyIdx].Key, ext->key, ext->key_len);
break;
case IW_ENCODE_ALG_TKIP:
- DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __FUNCTION__, keyIdx, ext->key_len));
+ DBGPRINT(RT_DEBUG_TRACE, ("%s::IW_ENCODE_ALG_TKIP - keyIdx = %d, ext->key_len = %d\n", __func__, keyIdx, ext->key_len));
if (ext->key_len == 32)
{
if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
diff --git a/drivers/staging/rtl8187se/ieee80211.h b/drivers/staging/rtl8187se/ieee80211.h
index bf06abeeaeb8..58336080ad50 100644
--- a/drivers/staging/rtl8187se/ieee80211.h
+++ b/drivers/staging/rtl8187se/ieee80211.h
@@ -396,7 +396,7 @@ extern u32 ieee80211_debug_level;
#define IEEE80211_DEBUG(level, fmt, args...) \
do { if (ieee80211_debug_level & (level)) \
printk(KERN_DEBUG "ieee80211: %c %s " fmt, \
- in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+ in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
#else
#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
#endif /* CONFIG_IEEE80211_DEBUG */
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
index bf06abeeaeb8..58336080ad50 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
@@ -396,7 +396,7 @@ extern u32 ieee80211_debug_level;
#define IEEE80211_DEBUG(level, fmt, args...) \
do { if (ieee80211_debug_level & (level)) \
printk(KERN_DEBUG "ieee80211: %c %s " fmt, \
- in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+ in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
#else
#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
#endif /* CONFIG_IEEE80211_DEBUG */
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c
index 7d890c328b0e..08add385790f 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c
@@ -490,7 +490,7 @@ static char * ieee80211_ccmp_print_stats(char *p, void *priv)
void ieee80211_ccmp_null(void)
{
-// printk("============>%s()\n", __FUNCTION__);
+// printk("============>%s()\n", __func__);
return;
}
static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = {
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c
index e560b1e11020..de97bbec0da5 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c
@@ -984,7 +984,7 @@ void ieee80211_crypto_tkip_exit(void)
void ieee80211_tkip_null(void)
{
-// printk("============>%s()\n", __FUNCTION__);
+// printk("============>%s()\n", __func__);
return;
}
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c
index f973daeeeb0f..68a22b32fcf0 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c
@@ -380,7 +380,7 @@ void ieee80211_crypto_wep_exit(void)
void ieee80211_wep_null(void)
{
-// printk("============>%s()\n", __FUNCTION__);
+// printk("============>%s()\n", __func__);
return;
}
#if 0
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
index 79ec64959cf6..23519b37538f 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c
@@ -1635,7 +1635,7 @@ inline void update_network(struct ieee80211_network *dst,
memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len);
dst->rates_ex_len = src->rates_ex_len;
dst->HighestOperaRate= src->HighestOperaRate;
- //printk("==========>in %s: src->ssid is %s,chan is %d\n",__FUNCTION__,src->ssid,src->channel);
+ //printk("==========>in %s: src->ssid is %s,chan is %d\n",__func__,src->ssid,src->channel);
//YJ,add,080819,for hidden ap
if(src->ssid_len > 0)
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
index fcffee516d51..e5752f615e09 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
@@ -731,7 +731,7 @@ void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee)
memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
#endif
// printk("ieee80211_softmac_scan_wq ENABLE_IPS\n");
-// printk("in %s\n",__FUNCTION__);
+// printk("in %s\n",__func__);
down(&ieee->scan_sem);
do{
@@ -1785,7 +1785,7 @@ void ieee80211_associate_step1(struct ieee80211_device *ieee)
//If call dev_kfree_skb_any,a warning will ocur....
//KERNEL: assertion (!atomic_read(&skb->users)) failed at net/core/dev.c (1708)
//So ... 1204 by lawrence.
- //printk("\nIn %s,line %d call kfree skb.",__FUNCTION__,__LINE__);
+ //printk("\nIn %s,line %d call kfree skb.",__func__,__LINE__);
//dev_kfree_skb_any(skb);//edit by thomas
}
}
@@ -2432,7 +2432,7 @@ inline void ieee80211_sta_ps(struct ieee80211_device *ieee)
}
sleep = ieee80211_sta_ps_sleep(ieee,&th, &tl);
-// printk("===>%s,%d[2 wake, 1 sleep, 0 do nothing], ieee->sta_sleep = %d\n",__FUNCTION__, sleep,ieee->sta_sleep);
+// printk("===>%s,%d[2 wake, 1 sleep, 0 do nothing], ieee->sta_sleep = %d\n",__func__, sleep,ieee->sta_sleep);
/* 2 wake, 1 sleep, 0 do nothing */
if(sleep == 0)
goto out;
@@ -2510,7 +2510,7 @@ void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success)
/* Null frame with PS bit set */
if(success){
- // printk("==================> %s::enter sleep state\n",__FUNCTION__);
+ // printk("==================> %s::enter sleep state\n",__func__);
ieee->sta_sleep = 1;
ieee->enter_sleep_state(ieee->dev,ieee->ps_th,ieee->ps_tl);
}
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
index 43b8aecee9de..93af37e2d31a 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
@@ -31,7 +31,7 @@ int ieee80211_wx_set_freq(struct ieee80211_device *ieee, struct iw_request_info
{
int ret;
struct iw_freq *fwrq = & wrqu->freq;
-// printk("in %s\n",__FUNCTION__);
+// printk("in %s\n",__func__);
down(&ieee->wx_sem);
if(ieee->iw_mode == IW_MODE_INFRA){
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
index c7d9f4fda413..6aad61e78041 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
@@ -663,7 +663,7 @@ int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
ret = -EINVAL;
goto done;
}
-// printk("8-09-08-9=====>%s, alg name:%s\n",__FUNCTION__, alg);
+// printk("8-09-08-9=====>%s, alg name:%s\n",__func__, alg);
ops = ieee80211_get_crypto_ops(alg);
if (ops == NULL) {
@@ -757,7 +757,7 @@ int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
union iwreq_data *wrqu, char *extra)
{
struct iw_mlme *mlme = (struct iw_mlme *) extra;
-// printk("\ndkgadfslkdjgalskdf===============>%s(), cmd:%x\n", __FUNCTION__, mlme->cmd);
+// printk("\ndkgadfslkdjgalskdf===============>%s(), cmd:%x\n", __func__, mlme->cmd);
#if 1
switch (mlme->cmd) {
case IW_MLME_DEAUTH:
@@ -830,7 +830,7 @@ int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
{
#if 0
- printk("====>%s()\n", __FUNCTION__);
+ printk("====>%s()\n", __func__);
{
int i;
for (i=0; i<len; i++)
@@ -866,7 +866,7 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
ieee->wpa_ie = NULL;
ieee->wpa_ie_len = 0;
}
-// printk("<=====out %s()\n", __FUNCTION__);
+// printk("<=====out %s()\n", __func__);
return 0;
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index 00f4df49bc0e..94534955e38b 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -1407,12 +1407,12 @@ void rtl8180_set_chan(struct net_device *dev,short ch)
if((ch > 14) || (ch < 1))
{
- printk("In %s: Invalid chnanel %d\n", __FUNCTION__, ch);
+ printk("In %s: Invalid chnanel %d\n", __func__, ch);
return;
}
priv->chan=ch;
- //printk("in %s:channel is %d\n",__FUNCTION__,ch);
+ //printk("in %s:channel is %d\n",__func__,ch);
priv->rf_set_chan(dev,priv->chan);
}
@@ -3656,7 +3656,7 @@ void rtl8180_link_change(struct net_device *dev)
void rtl8180_rq_tx_ack(struct net_device *dev){
struct r8180_priv *priv = ieee80211_priv(dev);
-// printk("====================>%s\n",__FUNCTION__);
+// printk("====================>%s\n",__func__);
write_nic_byte(dev,CONFIG4,read_nic_byte(dev,CONFIG4)|CONFIG4_PWRMGT);
priv->ack_tx_to_ieee = 1;
}
@@ -5448,7 +5448,7 @@ void rtl8180_hw_wakeup_wq(struct net_device *dev)
#endif
// printk("dev is %d\n",dev);
-// printk("&*&(^*(&(&=========>%s()\n", __FUNCTION__);
+// printk("&*&(^*(&(&=========>%s()\n", __func__);
rtl8180_hw_wakeup(dev);
}
@@ -6318,12 +6318,12 @@ priv->txnpring)/8);
// printk("NumTxOkTotal is %d\n",priv->NumTxOkTotal++);
}
#endif
- // printk("in function %s:curr_retry_count is %d\n",__FUNCTION__,((*head) & (0x000000ff)));
+ // printk("in function %s:curr_retry_count is %d\n",__func__,((*head) & (0x000000ff)));
}
if(!error){
priv->NumTxOkBytesTotal += (*(head+3)) & (0x00000fff);
}
-// printk("in function %s:curr_txokbyte_count is %d\n",__FUNCTION__,(*(head+3)) & (0x00000fff));
+// printk("in function %s:curr_txokbyte_count is %d\n",__func__,(*(head+3)) & (0x00000fff));
*head = *head &~ (1<<31);
if((head - begin)/8 == priv->txringcount-1)
diff --git a/drivers/staging/rtl8187se/r8180_rtl8225z2.c b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
index 90a574d46da0..4136b9429597 100644
--- a/drivers/staging/rtl8187se/r8180_rtl8225z2.c
+++ b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
@@ -1571,7 +1571,7 @@ void rtl8225z4_rf_sleep(struct net_device *dev)
//
// Turn off RF power.
//
- //printk("=========>%s()\n", __FUNCTION__);
+ //printk("=========>%s()\n", __func__);
MgntActSet_RF_State(dev, eRfSleep, RF_CHANGE_BY_PS);
//mdelay(2); //FIXME
}
@@ -1580,7 +1580,7 @@ void rtl8225z4_rf_wakeup(struct net_device *dev)
//
// Turn on RF power.
//
- //printk("=========>%s()\n", __FUNCTION__);
+ //printk("=========>%s()\n", __func__);
MgntActSet_RF_State(dev, eRfOn, RF_CHANGE_BY_PS);
}
#endif
diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c
index c77abe502b79..8b3901d87f87 100644
--- a/drivers/staging/rtl8187se/r8180_wx.c
+++ b/drivers/staging/rtl8187se/r8180_wx.c
@@ -1177,7 +1177,7 @@ static int r8180_wx_set_channelplan(struct net_device *dev,
//struct ieee80211_device *ieee = netdev_priv(dev);
int *val = (int *)extra;
int i;
- printk("-----in fun %s\n", __FUNCTION__);
+ printk("-----in fun %s\n", __func__);
if(priv->ieee80211->bHwRadioOff)
return 0;
@@ -1235,7 +1235,7 @@ static int r8180_wx_set_forcerate(struct net_device *dev,
down(&priv->wx_sem);
- printk("==============>%s(): forcerate is %d\n",__FUNCTION__,forcerate);
+ printk("==============>%s(): forcerate is %d\n",__func__,forcerate);
if((forcerate == 2) || (forcerate == 4) || (forcerate == 11) || (forcerate == 22) || (forcerate == 12) ||
(forcerate == 18) || (forcerate == 24) || (forcerate == 36) || (forcerate == 48) || (forcerate == 72) ||
(forcerate == 96) || (forcerate == 108))
@@ -1260,7 +1260,7 @@ static int r8180_wx_set_enc_ext(struct net_device *dev,
{
struct r8180_priv *priv = ieee80211_priv(dev);
- //printk("===>%s()\n", __FUNCTION__);
+ //printk("===>%s()\n", __func__);
int ret=0;
@@ -1277,7 +1277,7 @@ static int r8180_wx_set_auth(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *data, char *extra)
{
- //printk("====>%s()\n", __FUNCTION__);
+ //printk("====>%s()\n", __func__);
struct r8180_priv *priv = ieee80211_priv(dev);
int ret=0;
@@ -1294,7 +1294,7 @@ static int r8180_wx_set_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- //printk("====>%s()\n", __FUNCTION__);
+ //printk("====>%s()\n", __func__);
int ret=0;
struct r8180_priv *priv = ieee80211_priv(dev);
@@ -1315,7 +1315,7 @@ static int r8180_wx_set_gen_ie(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
{
-// printk("====>%s(), len:%d\n", __FUNCTION__, data->length);
+// printk("====>%s(), len:%d\n", __func__, data->length);
int ret=0;
struct r8180_priv *priv = ieee80211_priv(dev);
@@ -1328,7 +1328,7 @@ static int r8180_wx_set_gen_ie(struct net_device *dev,
ret = ieee80211_wx_set_gen_ie(priv->ieee80211, extra, data->length);
#endif
up(&priv->wx_sem);
- //printk("<======%s(), ret:%d\n", __FUNCTION__, ret);
+ //printk("<======%s(), ret:%d\n", __func__, ret);
return ret;
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 289d81adfb9c..83babb0a1df7 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -150,4 +150,6 @@ source "drivers/usb/atm/Kconfig"
source "drivers/usb/gadget/Kconfig"
+source "drivers/usb/otg/Kconfig"
+
endif # USB_SUPPORT
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index d50a99f70aee..00b47ea24f86 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1275,7 +1275,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
struct acm *acm = usb_get_intfdata(intf);
int cnt;
- if (acm->dev->auto_pm) {
+ if (message.event & PM_EVENT_AUTO) {
int b;
spin_lock_irq(&acm->read_lock);
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 5a8ecc045e3f..3771d6e6d0cc 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -764,7 +764,8 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
mutex_lock(&desc->plock);
#ifdef CONFIG_PM
- if (interface_to_usbdev(desc->intf)->auto_pm && test_bit(WDM_IN_USE, &desc->flags)) {
+ if ((message.event & PM_EVENT_AUTO) &&
+ test_bit(WDM_IN_USE, &desc->flags)) {
rv = -EBUSY;
} else {
#endif
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 43a863c5cc43..0f5c05f6f9df 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/kref.h>
@@ -482,7 +483,6 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
int retval;
int actual;
unsigned long int n_bytes;
- int n;
int remaining;
int done;
int this_part;
@@ -526,11 +526,8 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
goto exit;
}
- n_bytes = 12 + this_part;
- if (this_part % 4)
- n_bytes += 4 - this_part % 4;
- for (n = 12 + this_part; n < n_bytes; n++)
- buffer[n] = 0;
+ n_bytes = roundup(12 + this_part, 4);
+ memset(buffer + 12 + this_part, 0, n_bytes - (12 + this_part));
retval = usb_bulk_msg(data->usb_dev,
usb_sndbulkpipe(data->usb_dev,
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index aa79280df15d..26fece124e0e 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -981,9 +981,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -EINVAL;
if (!uurb->buffer)
return -EINVAL;
- if (uurb->signr != 0 && (uurb->signr < SIGRTMIN ||
- uurb->signr > SIGRTMAX))
- return -EINVAL;
if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL &&
(uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
ifnum = findintfep(ps->dev, uurb->endpoint);
@@ -1320,7 +1317,7 @@ static int get_urb32(struct usbdevfs_urb *kurb,
if (__get_user(uptr, &uurb->buffer))
return -EFAULT;
kurb->buffer = compat_ptr(uptr);
- if (__get_user(uptr, &uurb->buffer))
+ if (__get_user(uptr, &uurb->usercontext))
return -EFAULT;
kurb->usercontext = compat_ptr(uptr);
@@ -1401,8 +1398,6 @@ static int proc_disconnectsignal(struct dev_state *ps, void __user *arg)
if (copy_from_user(&ds, arg, sizeof(ds)))
return -EFAULT;
- if (ds.signr != 0 && (ds.signr < SIGRTMIN || ds.signr > SIGRTMAX))
- return -EINVAL;
ps->discsignr = ds.signr;
ps->disccontext = ds.context;
return 0;
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 8c081308b0e2..98760553bc95 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -184,6 +184,20 @@ static int usb_unbind_device(struct device *dev)
return 0;
}
+/*
+ * Cancel any pending scheduled resets
+ *
+ * [see usb_queue_reset_device()]
+ *
+ * Called after unconfiguring / when releasing interfaces. See
+ * comments in __usb_queue_reset_device() regarding
+ * udev->reset_running.
+ */
+static void usb_cancel_queued_reset(struct usb_interface *iface)
+{
+ if (iface->reset_running == 0)
+ cancel_work_sync(&iface->reset_ws);
+}
/* called from driver core with dev locked */
static int usb_probe_interface(struct device *dev)
@@ -242,6 +256,7 @@ static int usb_probe_interface(struct device *dev)
mark_quiesced(intf);
intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
+ usb_cancel_queued_reset(intf);
} else
intf->condition = USB_INTERFACE_BOUND;
@@ -272,6 +287,7 @@ static int usb_unbind_interface(struct device *dev)
usb_disable_interface(udev, intf);
driver->disconnect(intf);
+ usb_cancel_queued_reset(intf);
/* Reset other interface state.
* We cannot do a Set-Interface if the device is suspended or
@@ -279,9 +295,12 @@ static int usb_unbind_interface(struct device *dev)
* altsetting means creating new endpoint device entries).
* When either of these happens, defer the Set-Interface.
*/
- if (intf->cur_altsetting->desc.bAlternateSetting == 0)
- ; /* Already in altsetting 0 so skip Set-Interface */
- else if (!error && intf->dev.power.status == DPM_ON)
+ if (intf->cur_altsetting->desc.bAlternateSetting == 0) {
+ /* Already in altsetting 0 so skip Set-Interface.
+ * Just re-enable it without affecting the endpoint toggles.
+ */
+ usb_enable_interface(udev, intf, false);
+ } else if (!error && intf->dev.power.status == DPM_ON)
usb_set_interface(udev, intf->altsetting[0].
desc.bInterfaceNumber, 0);
else
@@ -380,8 +399,10 @@ void usb_driver_release_interface(struct usb_driver *driver,
if (device_is_registered(dev)) {
iface->condition = USB_INTERFACE_UNBINDING;
device_release_driver(dev);
+ } else {
+ iface->condition = USB_INTERFACE_UNBOUND;
+ usb_cancel_queued_reset(iface);
}
-
dev->driver = NULL;
usb_set_intfdata(iface, NULL);
@@ -904,7 +925,7 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
}
/* Caller has locked udev's pm_mutex */
-static int usb_resume_device(struct usb_device *udev)
+static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
{
struct usb_device_driver *udriver;
int status = 0;
@@ -922,7 +943,7 @@ static int usb_resume_device(struct usb_device *udev)
udev->reset_resume = 1;
udriver = to_usb_device_driver(udev->dev.driver);
- status = udriver->resume(udev);
+ status = udriver->resume(udev, msg);
done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
@@ -942,7 +963,8 @@ static int usb_suspend_interface(struct usb_device *udev,
if (udev->state == USB_STATE_NOTATTACHED || !is_active(intf))
goto done;
- if (intf->condition == USB_INTERFACE_UNBOUND) /* This can't happen */
+ /* This can happen; see usb_driver_release_interface() */
+ if (intf->condition == USB_INTERFACE_UNBOUND)
goto done;
driver = to_usb_driver(intf->dev.driver);
@@ -950,7 +972,7 @@ static int usb_suspend_interface(struct usb_device *udev,
status = driver->suspend(intf, msg);
if (status == 0)
mark_quiesced(intf);
- else if (!udev->auto_pm)
+ else if (!(msg.event & PM_EVENT_AUTO))
dev_err(&intf->dev, "%s error %d\n",
"suspend", status);
} else {
@@ -968,7 +990,7 @@ static int usb_suspend_interface(struct usb_device *udev,
/* Caller has locked intf's usb_device's pm_mutex */
static int usb_resume_interface(struct usb_device *udev,
- struct usb_interface *intf, int reset_resume)
+ struct usb_interface *intf, pm_message_t msg, int reset_resume)
{
struct usb_driver *driver;
int status = 0;
@@ -1092,7 +1114,7 @@ static int autosuspend_check(struct usb_device *udev, int reschedule)
if (reschedule) {
if (!timer_pending(&udev->autosuspend.timer)) {
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
- round_jiffies_relative(suspend_time - j));
+ round_jiffies_up_relative(suspend_time - j));
}
return -EAGAIN;
}
@@ -1119,10 +1141,9 @@ static inline int autosuspend_check(struct usb_device *udev, int reschedule)
* all the interfaces which were suspended are resumed so that they remain
* in the same state as the device.
*
- * If an autosuspend is in progress (@udev->auto_pm is set), the routine
- * checks first to make sure that neither the device itself or any of its
- * active interfaces is in use (pm_usage_cnt is greater than 0). If they
- * are, the autosuspend fails.
+ * If an autosuspend is in progress the routine checks first to make sure
+ * that neither the device itself or any of its active interfaces is in use
+ * (pm_usage_cnt is greater than 0). If they are, the autosuspend fails.
*
* If the suspend succeeds, the routine recursively queues an autosuspend
* request for @udev's parent device, thereby propagating the change up
@@ -1157,7 +1178,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
- if (udev->auto_pm) {
+ if (msg.event & PM_EVENT_AUTO) {
status = autosuspend_check(udev, 0);
if (status < 0)
goto done;
@@ -1177,13 +1198,16 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
+ pm_message_t msg2;
+
+ msg2.event = msg.event ^ (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
while (--i >= 0) {
intf = udev->actconfig->interface[i];
- usb_resume_interface(udev, intf, 0);
+ usb_resume_interface(udev, intf, msg2, 0);
}
/* Try another autosuspend when the interfaces aren't busy */
- if (udev->auto_pm)
+ if (msg.event & PM_EVENT_AUTO)
autosuspend_check(udev, status == -EBUSY);
/* If the suspend succeeded then prevent any more URB submissions,
@@ -1213,6 +1237,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
/**
* usb_resume_both - resume a USB device and its interfaces
* @udev: the usb_device to resume
+ * @msg: Power Management message describing this state transition
*
* This is the central routine for resuming USB devices. It calls the
* the resume method for @udev and then calls the resume methods for all
@@ -1238,7 +1263,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
*
* This routine can run only in process context.
*/
-static int usb_resume_both(struct usb_device *udev)
+static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
{
int status = 0;
int i;
@@ -1254,14 +1279,15 @@ static int usb_resume_both(struct usb_device *udev)
/* Propagate the resume up the tree, if necessary */
if (udev->state == USB_STATE_SUSPENDED) {
- if (udev->auto_pm && udev->autoresume_disabled) {
+ if ((msg.event & PM_EVENT_AUTO) &&
+ udev->autoresume_disabled) {
status = -EPERM;
goto done;
}
if (parent) {
status = usb_autoresume_device(parent);
if (status == 0) {
- status = usb_resume_device(udev);
+ status = usb_resume_device(udev, msg);
if (status || udev->state ==
USB_STATE_NOTATTACHED) {
usb_autosuspend_device(parent);
@@ -1284,15 +1310,16 @@ static int usb_resume_both(struct usb_device *udev)
/* We can't progagate beyond the USB subsystem,
* so if a root hub's controller is suspended
* then we're stuck. */
- status = usb_resume_device(udev);
+ status = usb_resume_device(udev, msg);
}
} else if (udev->reset_resume)
- status = usb_resume_device(udev);
+ status = usb_resume_device(udev, msg);
if (status == 0 && udev->actconfig) {
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
intf = udev->actconfig->interface[i];
- usb_resume_interface(udev, intf, udev->reset_resume);
+ usb_resume_interface(udev, intf, msg,
+ udev->reset_resume);
}
}
@@ -1320,13 +1347,13 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
udev->last_busy = jiffies;
if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) {
if (udev->state == USB_STATE_SUSPENDED)
- status = usb_resume_both(udev);
+ status = usb_resume_both(udev, PMSG_AUTO_RESUME);
if (status != 0)
udev->pm_usage_cnt -= inc_usage_cnt;
else if (inc_usage_cnt)
udev->last_busy = jiffies;
} else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) {
- status = usb_suspend_both(udev, PMSG_SUSPEND);
+ status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
}
usb_pm_unlock(udev);
return status;
@@ -1341,6 +1368,19 @@ void usb_autosuspend_work(struct work_struct *work)
usb_autopm_do_device(udev, 0);
}
+/* usb_autoresume_work - callback routine to autoresume a USB device */
+void usb_autoresume_work(struct work_struct *work)
+{
+ struct usb_device *udev =
+ container_of(work, struct usb_device, autoresume);
+
+ /* Wake it up, let the drivers do their thing, and then put it
+ * back to sleep.
+ */
+ if (usb_autopm_do_device(udev, 1) == 0)
+ usb_autopm_do_device(udev, -1);
+}
+
/**
* usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
* @udev: the usb_device to autosuspend
@@ -1437,13 +1477,14 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
udev->last_busy = jiffies;
if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) {
if (udev->state == USB_STATE_SUSPENDED)
- status = usb_resume_both(udev);
+ status = usb_resume_both(udev,
+ PMSG_AUTO_RESUME);
if (status != 0)
intf->pm_usage_cnt -= inc_usage_cnt;
else
udev->last_busy = jiffies;
} else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) {
- status = usb_suspend_both(udev, PMSG_SUSPEND);
+ status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
}
}
usb_pm_unlock(udev);
@@ -1492,6 +1533,45 @@ void usb_autopm_put_interface(struct usb_interface *intf)
EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
/**
+ * usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be decremented
+ *
+ * This routine does essentially the same thing as
+ * usb_autopm_put_interface(): it decrements @intf's usage counter and
+ * queues a delayed autosuspend request if the counter is <= 0. The
+ * difference is that it does not acquire the device's pm_mutex;
+ * callers must handle all synchronization issues themselves.
+ *
+ * Typically a driver would call this routine during an URB's completion
+ * handler, if no more URBs were pending.
+ *
+ * This routine can run in atomic context.
+ */
+void usb_autopm_put_interface_async(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int status = 0;
+
+ if (intf->condition == USB_INTERFACE_UNBOUND) {
+ status = -ENODEV;
+ } else {
+ udev->last_busy = jiffies;
+ --intf->pm_usage_cnt;
+ if (udev->autosuspend_disabled || udev->autosuspend_delay < 0)
+ status = -EPERM;
+ else if (intf->pm_usage_cnt <= 0 &&
+ !timer_pending(&udev->autosuspend.timer)) {
+ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
+ round_jiffies_up_relative(
+ udev->autosuspend_delay));
+ }
+ }
+ dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+ __func__, status, intf->pm_usage_cnt);
+}
+EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
+
+/**
* usb_autopm_get_interface - increment a USB interface's PM-usage counter
* @intf: the usb_interface whose counter should be incremented
*
@@ -1537,6 +1617,37 @@ int usb_autopm_get_interface(struct usb_interface *intf)
EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
/**
+ * usb_autopm_get_interface_async - increment a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be incremented
+ *
+ * This routine does much the same thing as
+ * usb_autopm_get_interface(): it increments @intf's usage counter and
+ * queues an autoresume request if the result is > 0. The differences
+ * are that it does not acquire the device's pm_mutex (callers must
+ * handle all synchronization issues themselves), and it does not
+ * autoresume the device directly (it only queues a request). After a
+ * successful call, the device will generally not yet be resumed.
+ *
+ * This routine can run in atomic context.
+ */
+int usb_autopm_get_interface_async(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int status = 0;
+
+ if (intf->condition == USB_INTERFACE_UNBOUND)
+ status = -ENODEV;
+ else if (udev->autoresume_disabled)
+ status = -EPERM;
+ else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED)
+ queue_work(ksuspend_usb_wq, &udev->autoresume);
+ dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+ __func__, status, intf->pm_usage_cnt);
+ return status;
+}
+EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
+
+/**
* usb_autopm_set_interface - set a USB interface's autosuspend state
* @intf: the usb_interface whose state should be set
*
@@ -1563,6 +1674,9 @@ EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
void usb_autosuspend_work(struct work_struct *work)
{}
+void usb_autoresume_work(struct work_struct *work)
+{}
+
#endif /* CONFIG_USB_SUSPEND */
/**
@@ -1595,6 +1709,7 @@ int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg)
/**
* usb_external_resume_device - external resume of a USB device and its interfaces
* @udev: the usb_device to resume
+ * @msg: Power Management message describing this state transition
*
* This routine handles external resume requests: ones not generated
* internally by a USB driver (autoresume) but rather coming from the user
@@ -1603,13 +1718,13 @@ int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg)
*
* The caller must hold @udev's device lock.
*/
-int usb_external_resume_device(struct usb_device *udev)
+int usb_external_resume_device(struct usb_device *udev, pm_message_t msg)
{
int status;
usb_pm_lock(udev);
udev->auto_pm = 0;
- status = usb_resume_both(udev);
+ status = usb_resume_both(udev, msg);
udev->last_busy = jiffies;
usb_pm_unlock(udev);
if (status == 0)
@@ -1622,7 +1737,7 @@ int usb_external_resume_device(struct usb_device *udev)
return status;
}
-int usb_suspend(struct device *dev, pm_message_t message)
+int usb_suspend(struct device *dev, pm_message_t msg)
{
struct usb_device *udev;
@@ -1641,10 +1756,10 @@ int usb_suspend(struct device *dev, pm_message_t message)
}
udev->skip_sys_resume = 0;
- return usb_external_suspend_device(udev, message);
+ return usb_external_suspend_device(udev, msg);
}
-int usb_resume(struct device *dev)
+int usb_resume(struct device *dev, pm_message_t msg)
{
struct usb_device *udev;
@@ -1656,7 +1771,7 @@ int usb_resume(struct device *dev)
*/
if (udev->skip_sys_resume)
return 0;
- return usb_external_resume_device(udev);
+ return usb_external_resume_device(udev, msg);
}
#endif /* CONFIG_PM */
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 946fae43d622..e1710f260b4f 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -276,7 +276,7 @@ static void ep_device_release(struct device *dev)
kfree(ep_dev);
}
-int usb_create_ep_files(struct device *parent,
+int usb_create_ep_devs(struct device *parent,
struct usb_host_endpoint *endpoint,
struct usb_device *udev)
{
@@ -340,7 +340,7 @@ exit:
return retval;
}
-void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
+void usb_remove_ep_devs(struct usb_host_endpoint *endpoint)
{
struct ep_device *ep_dev = endpoint->ep_dev;
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 7e912f21fd36..30ecac3af15a 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -200,18 +200,18 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
* interfaces manually by doing a bus (or "global") suspend.
*/
if (!udev->parent)
- rc = hcd_bus_suspend(udev);
+ rc = hcd_bus_suspend(udev, msg);
/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
rc = 0;
else
- rc = usb_port_suspend(udev);
+ rc = usb_port_suspend(udev, msg);
return rc;
}
-static int generic_resume(struct usb_device *udev)
+static int generic_resume(struct usb_device *udev, pm_message_t msg)
{
int rc;
@@ -221,9 +221,9 @@ static int generic_resume(struct usb_device *udev)
* interfaces manually by doing a bus (or "global") resume.
*/
if (!udev->parent)
- rc = hcd_bus_resume(udev);
+ rc = hcd_bus_resume(udev, msg);
else
- rc = usb_port_resume(udev);
+ rc = usb_port_resume(udev, msg);
return rc;
}
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 5b87ae7f0a6a..507741ed4482 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -128,6 +128,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
}
pci_set_master(dev);
+ device_set_wakeup_enable(&dev->dev, 1);
retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
if (retval != 0)
@@ -191,17 +192,15 @@ EXPORT_SYMBOL_GPL(usb_hcd_pci_remove);
/**
* usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
* @dev: USB Host Controller being suspended
- * @message: semantics in flux
+ * @message: Power Management message describing this state transition
*
- * Store this function in the HCD's struct pci_driver as suspend().
+ * Store this function in the HCD's struct pci_driver as .suspend.
*/
int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
{
- struct usb_hcd *hcd;
+ struct usb_hcd *hcd = pci_get_drvdata(dev);
int retval = 0;
- int has_pci_pm;
-
- hcd = pci_get_drvdata(dev);
+ int wake, w;
/* Root hub suspend should have stopped all downstream traffic,
* and all bus master traffic. And done so for both the interface
@@ -212,8 +211,15 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
* otherwise the swsusp will save (and restore) garbage state.
*/
if (!(hcd->state == HC_STATE_SUSPENDED ||
- hcd->state == HC_STATE_HALT))
- return -EBUSY;
+ hcd->state == HC_STATE_HALT)) {
+ dev_warn(&dev->dev, "Root hub is not suspended\n");
+ retval = -EBUSY;
+ goto done;
+ }
+
+ /* We might already be suspended (runtime PM -- not yet written) */
+ if (dev->current_state != PCI_D0)
+ goto done;
if (hcd->driver->pci_suspend) {
retval = hcd->driver->pci_suspend(hcd, message);
@@ -221,49 +227,60 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
if (retval)
goto done;
}
- synchronize_irq(dev->irq);
- /* FIXME until the generic PM interfaces change a lot more, this
- * can't use PCI D1 and D2 states. For example, the confusion
- * between messages and states will need to vanish, and messages
- * will need to provide a target system state again.
- *
- * It'll be important to learn characteristics of the target state,
- * especially on embedded hardware where the HCD will often be in
- * charge of an external VBUS power supply and one or more clocks.
- * Some target system states will leave them active; others won't.
- * (With PCI, that's often handled by platform BIOS code.)
- */
+ synchronize_irq(dev->irq);
- /* even when the PCI layer rejects some of the PCI calls
- * below, HCs can try global suspend and reduce DMA traffic.
- * PM-sensitive HCDs may already have done this.
+ /* Don't fail on error to enable wakeup. We rely on pci code
+ * to reject requests the hardware can't implement, rather
+ * than coding the same thing.
*/
- has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ wake = (hcd->state == HC_STATE_SUSPENDED &&
+ device_may_wakeup(&dev->dev));
+ w = pci_wake_from_d3(dev, wake);
+ if (w < 0)
+ wake = w;
+ dev_dbg(&dev->dev, "wakeup: %d\n", wake);
/* Downstream ports from this root hub should already be quiesced, so
* there will be no DMA activity. Now we can shut down the upstream
* link (except maybe for PME# resume signaling) and enter some PCI
* low power state, if the hardware allows.
*/
- if (hcd->state == HC_STATE_SUSPENDED) {
+ pci_disable_device(dev);
+ done:
+ return retval;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend);
- /* no DMA or IRQs except when HC is active */
- if (dev->current_state == PCI_D0) {
- pci_save_state(dev);
- pci_disable_device(dev);
- }
+/**
+ * usb_hcd_pci_suspend_late - suspend a PCI-based HCD after IRQs are disabled
+ * @dev: USB Host Controller being suspended
+ * @message: Power Management message describing this state transition
+ *
+ * Store this function in the HCD's struct pci_driver as .suspend_late.
+ */
+int usb_hcd_pci_suspend_late(struct pci_dev *dev, pm_message_t message)
+{
+ int retval = 0;
+ int has_pci_pm;
- if (message.event == PM_EVENT_FREEZE ||
- message.event == PM_EVENT_PRETHAW) {
- dev_dbg(hcd->self.controller, "--> no state change\n");
- goto done;
- }
+ /* We might already be suspended (runtime PM -- not yet written) */
+ if (dev->current_state != PCI_D0)
+ goto done;
- if (!has_pci_pm) {
- dev_dbg(hcd->self.controller, "--> PCI D0/legacy\n");
- goto done;
- }
+ pci_save_state(dev);
+
+ /* Don't change state if we don't need to */
+ if (message.event == PM_EVENT_FREEZE ||
+ message.event == PM_EVENT_PRETHAW) {
+ dev_dbg(&dev->dev, "--> no state change\n");
+ goto done;
+ }
+
+ has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+ if (!has_pci_pm) {
+ dev_dbg(&dev->dev, "--> PCI D0 legacy\n");
+ } else {
/* NOTE: dev->current_state becomes nonzero only here, and
* only for devices that support PCI PM. Also, exiting
@@ -273,35 +290,16 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
retval = pci_set_power_state(dev, PCI_D3hot);
suspend_report_result(pci_set_power_state, retval);
if (retval == 0) {
- int wake = device_can_wakeup(&hcd->self.root_hub->dev);
-
- wake = wake && device_may_wakeup(hcd->self.controller);
-
- dev_dbg(hcd->self.controller, "--> PCI D3%s\n",
- wake ? "/wakeup" : "");
-
- /* Ignore these return values. We rely on pci code to
- * reject requests the hardware can't implement, rather
- * than coding the same thing.
- */
- (void) pci_enable_wake(dev, PCI_D3hot, wake);
- (void) pci_enable_wake(dev, PCI_D3cold, wake);
+ dev_dbg(&dev->dev, "--> PCI D3\n");
} else {
dev_dbg(&dev->dev, "PCI D3 suspend fail, %d\n",
retval);
- (void) usb_hcd_pci_resume(dev);
+ pci_restore_state(dev);
}
-
- } else if (hcd->state != HC_STATE_HALT) {
- dev_dbg(hcd->self.controller, "hcd state %d; not suspended\n",
- hcd->state);
- WARN_ON(1);
- retval = -EINVAL;
}
-done:
- if (retval == 0) {
#ifdef CONFIG_PPC_PMAC
+ if (retval == 0) {
/* Disable ASIC clocks for USB */
if (machine_is(powermac)) {
struct device_node *of_node;
@@ -311,30 +309,24 @@ done:
pmac_call_feature(PMAC_FTR_USB_ENABLE,
of_node, 0, 0);
}
-#endif
}
+#endif
+ done:
return retval;
}
-EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend);
+EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend_late);
/**
- * usb_hcd_pci_resume - power management resume of a PCI-based HCD
+ * usb_hcd_pci_resume_early - resume a PCI-based HCD before IRQs are enabled
* @dev: USB Host Controller being resumed
*
- * Store this function in the HCD's struct pci_driver as resume().
+ * Store this function in the HCD's struct pci_driver as .resume_early.
*/
-int usb_hcd_pci_resume(struct pci_dev *dev)
+int usb_hcd_pci_resume_early(struct pci_dev *dev)
{
- struct usb_hcd *hcd;
- int retval;
-
- hcd = pci_get_drvdata(dev);
- if (hcd->state != HC_STATE_SUSPENDED) {
- dev_dbg(hcd->self.controller,
- "can't resume, not suspended!\n");
- return 0;
- }
+ int retval = 0;
+ pci_power_t state = dev->current_state;
#ifdef CONFIG_PPC_PMAC
/* Reenable ASIC clocks for USB */
@@ -352,7 +344,7 @@ int usb_hcd_pci_resume(struct pci_dev *dev)
* calls "standby", "suspend to RAM", and so on). There are also
* dirty cases when swsusp fakes a suspend in "shutdown" mode.
*/
- if (dev->current_state != PCI_D0) {
+ if (state != PCI_D0) {
#ifdef DEBUG
int pci_pm;
u16 pmcr;
@@ -364,8 +356,7 @@ int usb_hcd_pci_resume(struct pci_dev *dev)
/* Clean case: power to USB and to HC registers was
* maintained; remote wakeup is easy.
*/
- dev_dbg(hcd->self.controller, "resume from PCI D%d\n",
- pmcr);
+ dev_dbg(&dev->dev, "resume from PCI D%d\n", pmcr);
} else {
/* Clean: HC lost Vcc power, D0 uninitialized
* + Vaux may have preserved port and transceiver
@@ -376,32 +367,55 @@ int usb_hcd_pci_resume(struct pci_dev *dev)
* + after BIOS init
* + after Linux init (HCD statically linked)
*/
- dev_dbg(hcd->self.controller,
- "PCI D0, from previous PCI D%d\n",
- dev->current_state);
+ dev_dbg(&dev->dev, "resume from previous PCI D%d\n",
+ state);
}
#endif
- /* yes, ignore these results too... */
- (void) pci_enable_wake(dev, dev->current_state, 0);
- (void) pci_enable_wake(dev, PCI_D3cold, 0);
+
+ retval = pci_set_power_state(dev, PCI_D0);
} else {
/* Same basic cases: clean (powered/not), dirty */
- dev_dbg(hcd->self.controller, "PCI legacy resume\n");
+ dev_dbg(&dev->dev, "PCI legacy resume\n");
+ }
+
+ if (retval < 0)
+ dev_err(&dev->dev, "can't resume: %d\n", retval);
+ else
+ pci_restore_state(dev);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_pci_resume_early);
+
+/**
+ * usb_hcd_pci_resume - power management resume of a PCI-based HCD
+ * @dev: USB Host Controller being resumed
+ *
+ * Store this function in the HCD's struct pci_driver as .resume.
+ */
+int usb_hcd_pci_resume(struct pci_dev *dev)
+{
+ struct usb_hcd *hcd;
+ int retval;
+
+ hcd = pci_get_drvdata(dev);
+ if (hcd->state != HC_STATE_SUSPENDED) {
+ dev_dbg(hcd->self.controller,
+ "can't resume, not suspended!\n");
+ return 0;
}
- /* NOTE: the PCI API itself is asymmetric here. We don't need to
- * pci_set_power_state(PCI_D0) since that's part of re-enabling;
- * but that won't re-enable bus mastering. Yet pci_disable_device()
- * explicitly disables bus mastering...
- */
retval = pci_enable_device(dev);
if (retval < 0) {
- dev_err(hcd->self.controller,
- "can't re-enable after resume, %d!\n", retval);
+ dev_err(&dev->dev, "can't re-enable after resume, %d!\n",
+ retval);
return retval;
}
+
pci_set_master(dev);
- pci_restore_state(dev);
+
+ /* yes, ignore this result too... */
+ (void) pci_wake_from_d3(dev, 0);
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
@@ -413,7 +427,6 @@ int usb_hcd_pci_resume(struct pci_dev *dev)
usb_hc_died(hcd);
}
}
-
return retval;
}
EXPORT_SYMBOL_GPL(usb_hcd_pci_resume);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index e1b42626d04d..3c711db55d86 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1010,7 +1010,7 @@ int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
spin_lock(&hcd_urb_list_lock);
/* Check that the URB isn't being killed */
- if (unlikely(urb->reject)) {
+ if (unlikely(atomic_read(&urb->reject))) {
rc = -EPERM;
goto done;
}
@@ -1340,7 +1340,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
INIT_LIST_HEAD(&urb->urb_list);
atomic_dec(&urb->use_count);
atomic_dec(&urb->dev->urbnum);
- if (urb->reject)
+ if (atomic_read(&urb->reject))
wake_up(&usb_kill_urb_queue);
usb_put_urb(urb);
}
@@ -1444,7 +1444,7 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
urb->status = status;
urb->complete (urb);
atomic_dec (&urb->use_count);
- if (unlikely (urb->reject))
+ if (unlikely(atomic_read(&urb->reject)))
wake_up (&usb_kill_urb_queue);
usb_put_urb (urb);
}
@@ -1573,14 +1573,14 @@ int usb_hcd_get_frame_number (struct usb_device *udev)
#ifdef CONFIG_PM
-int hcd_bus_suspend(struct usb_device *rhdev)
+int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
{
struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
int status;
int old_state = hcd->state;
dev_dbg(&rhdev->dev, "bus %s%s\n",
- rhdev->auto_pm ? "auto-" : "", "suspend");
+ (msg.event & PM_EVENT_AUTO ? "auto-" : ""), "suspend");
if (!hcd->driver->bus_suspend) {
status = -ENOENT;
} else {
@@ -1598,14 +1598,14 @@ int hcd_bus_suspend(struct usb_device *rhdev)
return status;
}
-int hcd_bus_resume(struct usb_device *rhdev)
+int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
{
struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
int status;
int old_state = hcd->state;
dev_dbg(&rhdev->dev, "usb %s%s\n",
- rhdev->auto_pm ? "auto-" : "", "resume");
+ (msg.event & PM_EVENT_AUTO ? "auto-" : ""), "resume");
if (!hcd->driver->bus_resume)
return -ENOENT;
if (hcd->state == HC_STATE_RUNNING)
@@ -1638,7 +1638,7 @@ static void hcd_resume_work(struct work_struct *work)
usb_lock_device(udev);
usb_mark_last_busy(udev);
- usb_external_resume_device(udev);
+ usb_external_resume_device(udev, PMSG_REMOTE_RESUME);
usb_unlock_device(udev);
}
@@ -2028,7 +2028,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown);
/*-------------------------------------------------------------------------*/
-#if defined(CONFIG_USB_MON)
+#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
struct usb_mon_operations *mon_ops;
@@ -2064,4 +2064,4 @@ void usb_mon_deregister (void)
}
EXPORT_SYMBOL_GPL (usb_mon_deregister);
-#endif /* CONFIG_USB_MON */
+#endif /* CONFIG_USB_MON || CONFIG_USB_MON_MODULE */
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 9465e70f4dd0..572d2cf46e8d 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -16,6 +16,8 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#ifndef __USB_CORE_HCD_H
+#define __USB_CORE_HCD_H
#ifdef __KERNEL__
@@ -254,7 +256,9 @@ extern int usb_hcd_pci_probe(struct pci_dev *dev,
extern void usb_hcd_pci_remove(struct pci_dev *dev);
#ifdef CONFIG_PM
-extern int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t state);
+extern int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t msg);
+extern int usb_hcd_pci_suspend_late(struct pci_dev *dev, pm_message_t msg);
+extern int usb_hcd_pci_resume_early(struct pci_dev *dev);
extern int usb_hcd_pci_resume(struct pci_dev *dev);
#endif /* CONFIG_PM */
@@ -386,8 +390,8 @@ extern int usb_find_interface_driver(struct usb_device *dev,
#ifdef CONFIG_PM
extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
extern void usb_root_hub_lost_power(struct usb_device *rhdev);
-extern int hcd_bus_suspend(struct usb_device *rhdev);
-extern int hcd_bus_resume(struct usb_device *rhdev);
+extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
+extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg);
#else
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
{
@@ -419,7 +423,7 @@ static inline void usbfs_cleanup(void) { }
/*-------------------------------------------------------------------------*/
-#if defined(CONFIG_USB_MON)
+#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
struct usb_mon_operations {
void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
@@ -461,7 +465,7 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
int status) {}
-#endif /* CONFIG_USB_MON */
+#endif /* CONFIG_USB_MON || CONFIG_USB_MON_MODULE */
/*-------------------------------------------------------------------------*/
@@ -490,3 +494,5 @@ extern struct rw_semaphore ehci_cf_port_reset_rwsem;
extern unsigned long usb_hcds_loaded;
#endif /* __KERNEL__ */
+
+#endif /* __USB_CORE_HCD_H */
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b19cbfcd51da..94d5ee263c20 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -107,7 +107,9 @@ MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs");
/* define initial 64-byte descriptor request timeout in milliseconds */
static int initial_descriptor_timeout = USB_CTRL_GET_TIMEOUT;
module_param(initial_descriptor_timeout, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(initial_descriptor_timeout, "initial 64-byte descriptor request timeout in milliseconds (default 5000 - 5.0 seconds)");
+MODULE_PARM_DESC(initial_descriptor_timeout,
+ "initial 64-byte descriptor request timeout in milliseconds "
+ "(default 5000 - 5.0 seconds)");
/*
* As of 2.6.10 we introduce a new USB device initialization scheme which
@@ -1136,8 +1138,8 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
hdev = interface_to_usbdev(intf);
if (hdev->level == MAX_TOPO_LEVEL) {
- dev_err(&intf->dev, "Unsupported bus topology: "
- "hub nested too deep\n");
+ dev_err(&intf->dev,
+ "Unsupported bus topology: hub nested too deep\n");
return -E2BIG;
}
@@ -1374,8 +1376,9 @@ static void usb_stop_pm(struct usb_device *udev)
usb_autosuspend_device(udev->parent);
usb_pm_unlock(udev);
- /* Stop any autosuspend requests already submitted */
- cancel_rearming_delayed_work(&udev->autosuspend);
+ /* Stop any autosuspend or autoresume requests already submitted */
+ cancel_delayed_work_sync(&udev->autosuspend);
+ cancel_work_sync(&udev->autoresume);
}
#else
@@ -1434,17 +1437,12 @@ void usb_disconnect(struct usb_device **pdev)
usb_disable_device(udev, 0);
usb_hcd_synchronize_unlinks(udev);
+ usb_remove_ep_devs(&udev->ep0);
usb_unlock_device(udev);
- /* Remove the device-specific files from sysfs. This must be
- * done with udev unlocked, because some of the attribute
- * routines try to acquire the device lock.
- */
- usb_remove_sysfs_dev_files(udev);
-
/* Unregister the device. The device driver is responsible
- * for removing the device files from usbfs and sysfs and for
- * de-configuring the device.
+ * for de-configuring the device and invoking the remove-device
+ * notifier chain (used by usbfs and possibly others).
*/
device_del(&udev->dev);
@@ -1476,8 +1474,8 @@ static void announce_device(struct usb_device *udev)
dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
- dev_info(&udev->dev, "New USB device strings: Mfr=%d, Product=%d, "
- "SerialNumber=%d\n",
+ dev_info(&udev->dev,
+ "New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
udev->descriptor.iManufacturer,
udev->descriptor.iProduct,
udev->descriptor.iSerialNumber);
@@ -1542,7 +1540,7 @@ static int usb_configure_device_otg(struct usb_device *udev)
* customize to match your product.
*/
dev_info(&udev->dev,
- "can't set HNP mode; %d\n",
+ "can't set HNP mode: %d\n",
err);
bus->b_hnp_enable = 0;
}
@@ -1556,7 +1554,7 @@ static int usb_configure_device_otg(struct usb_device *udev)
* (Includes HNP test device.)
*/
if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
- err = usb_port_suspend(udev);
+ err = usb_port_suspend(udev, PMSG_SUSPEND);
if (err < 0)
dev_dbg(&udev->dev, "HNP fail, %d\n", err);
}
@@ -1635,6 +1633,10 @@ int usb_new_device(struct usb_device *udev)
{
int err;
+ /* Increment the parent's count of unsuspended children */
+ if (udev->parent)
+ usb_autoresume_device(udev->parent);
+
usb_detect_quirks(udev); /* Determine quirks */
err = usb_configure_device(udev); /* detect & probe dev/intfs */
if (err < 0)
@@ -1643,13 +1645,12 @@ int usb_new_device(struct usb_device *udev)
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
- /* Increment the parent's count of unsuspended children */
- if (udev->parent)
- usb_autoresume_device(udev->parent);
+ /* Tell the world! */
+ announce_device(udev);
/* Register the device. The device driver is responsible
- * for adding the device files to sysfs and for configuring
- * the device.
+ * for configuring the device and invoking the add-device
+ * notifier chain (used by usbfs and possibly others).
*/
err = device_add(&udev->dev);
if (err) {
@@ -1657,15 +1658,12 @@ int usb_new_device(struct usb_device *udev)
goto fail;
}
- /* put device-specific files into sysfs */
- usb_create_sysfs_dev_files(udev);
-
- /* Tell the world! */
- announce_device(udev);
+ (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev);
return err;
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
+ usb_stop_pm(udev);
return err;
}
@@ -1982,7 +1980,7 @@ static int check_port_resume_type(struct usb_device *udev,
*
* Returns 0 on success, else negative errno.
*/
-int usb_port_suspend(struct usb_device *udev)
+int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
{
struct usb_hub *hub = hdev_to_hub(udev->parent);
int port1 = udev->portnum;
@@ -2021,7 +2019,7 @@ int usb_port_suspend(struct usb_device *udev)
} else {
/* device has up to 10 msec to fully suspend */
dev_dbg(&udev->dev, "usb %ssuspend\n",
- udev->auto_pm ? "auto-" : "");
+ (msg.event & PM_EVENT_AUTO ? "auto-" : ""));
usb_set_device_state(udev, USB_STATE_SUSPENDED);
msleep(10);
}
@@ -2045,8 +2043,8 @@ static int finish_port_resume(struct usb_device *udev)
u16 devstatus;
/* caller owns the udev device lock */
- dev_dbg(&udev->dev, "finish %sresume\n",
- udev->reset_resume ? "reset-" : "");
+ dev_dbg(&udev->dev, "%s\n",
+ udev->reset_resume ? "finish reset-resume" : "finish resume");
/* usb ch9 identifies four variants of SUSPENDED, based on what
* state the device resumes to. Linux currently won't see the
@@ -2098,8 +2096,9 @@ static int finish_port_resume(struct usb_device *udev)
NULL, 0,
USB_CTRL_SET_TIMEOUT);
if (status)
- dev_dbg(&udev->dev, "disable remote "
- "wakeup, status %d\n", status);
+ dev_dbg(&udev->dev,
+ "disable remote wakeup, status %d\n",
+ status);
}
status = 0;
}
@@ -2140,7 +2139,7 @@ static int finish_port_resume(struct usb_device *udev)
*
* Returns 0 on success, else negative errno.
*/
-int usb_port_resume(struct usb_device *udev)
+int usb_port_resume(struct usb_device *udev, pm_message_t msg)
{
struct usb_hub *hub = hdev_to_hub(udev->parent);
int port1 = udev->portnum;
@@ -2165,7 +2164,7 @@ int usb_port_resume(struct usb_device *udev)
} else {
/* drive resume for at least 20 msec */
dev_dbg(&udev->dev, "usb %sresume\n",
- udev->auto_pm ? "auto-" : "");
+ (msg.event & PM_EVENT_AUTO ? "auto-" : ""));
msleep(25);
/* Virtual root hubs can trigger on GET_PORT_STATUS to
@@ -2206,7 +2205,7 @@ static int remote_wakeup(struct usb_device *udev)
if (udev->state == USB_STATE_SUSPENDED) {
dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
usb_mark_last_busy(udev);
- status = usb_external_resume_device(udev);
+ status = usb_external_resume_device(udev, PMSG_REMOTE_RESUME);
}
return status;
}
@@ -2215,14 +2214,14 @@ static int remote_wakeup(struct usb_device *udev)
/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */
-int usb_port_suspend(struct usb_device *udev)
+int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
{
return 0;
}
/* However we may need to do a reset-resume */
-int usb_port_resume(struct usb_device *udev)
+int usb_port_resume(struct usb_device *udev, pm_message_t msg)
{
struct usb_hub *hub = hdev_to_hub(udev->parent);
int port1 = udev->portnum;
@@ -2262,7 +2261,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
udev = hdev->children [port1-1];
if (udev && udev->can_submit) {
- if (!hdev->auto_pm)
+ if (!(msg.event & PM_EVENT_AUTO))
dev_dbg(&intf->dev, "port %d nyet suspended\n",
port1);
return -EBUSY;
@@ -2385,7 +2384,7 @@ void usb_ep0_reinit(struct usb_device *udev)
{
usb_disable_endpoint(udev, 0 + USB_DIR_IN);
usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
- usb_enable_endpoint(udev, &udev->ep0);
+ usb_enable_endpoint(udev, &udev->ep0, true);
}
EXPORT_SYMBOL_GPL(usb_ep0_reinit);
@@ -2582,9 +2581,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}
if (r) {
- dev_err(&udev->dev, "device descriptor "
- "read/%s, error %d\n",
- "64", r);
+ dev_err(&udev->dev,
+ "device descriptor read/64, error %d\n",
+ r);
retval = -EMSGSIZE;
continue;
}
@@ -2621,9 +2620,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = usb_get_device_descriptor(udev, 8);
if (retval < 8) {
- dev_err(&udev->dev, "device descriptor "
- "read/%s, error %d\n",
- "8", retval);
+ dev_err(&udev->dev,
+ "device descriptor read/8, error %d\n",
+ retval);
if (retval >= 0)
retval = -EMSGSIZE;
} else {
@@ -2650,8 +2649,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
if (retval < (signed)sizeof(udev->descriptor)) {
- dev_err(&udev->dev, "device descriptor read/%s, error %d\n",
- "all", retval);
+ dev_err(&udev->dev, "device descriptor read/all, error %d\n",
+ retval);
if (retval >= 0)
retval = -ENOMSG;
goto fail;
@@ -2719,9 +2718,9 @@ hub_power_remaining (struct usb_hub *hub)
else
delta = 8;
if (delta > hub->mA_per_port)
- dev_warn(&udev->dev, "%dmA is over %umA budget "
- "for port %d!\n",
- delta, hub->mA_per_port, port1);
+ dev_warn(&udev->dev,
+ "%dmA is over %umA budget for port %d!\n",
+ delta, hub->mA_per_port, port1);
remaining -= delta;
}
if (remaining < 0) {
@@ -3517,3 +3516,46 @@ int usb_reset_device(struct usb_device *udev)
return ret;
}
EXPORT_SYMBOL_GPL(usb_reset_device);
+
+
+/**
+ * usb_queue_reset_device - Reset a USB device from an atomic context
+ * @iface: USB interface belonging to the device to reset
+ *
+ * This function can be used to reset a USB device from an atomic
+ * context, where usb_reset_device() won't work (as it blocks).
+ *
+ * Doing a reset via this method is functionally equivalent to calling
+ * usb_reset_device(), except for the fact that it is delayed to a
+ * workqueue. This means that any drivers bound to other interfaces
+ * might be unbound, as well as users from usbfs in user space.
+ *
+ * Corner cases:
+ *
+ * - Scheduling two resets at the same time from two different drivers
+ * attached to two different interfaces of the same device is
+ * possible; depending on how the driver attached to each interface
+ * handles ->pre_reset(), the second reset might happen or not.
+ *
+ * - If a driver is unbound and it had a pending reset, the reset will
+ * be cancelled.
+ *
+ * - This function can be called during .probe() or .disconnect()
+ * times. On return from .disconnect(), any pending resets will be
+ * cancelled.
+ *
+ * There is no no need to lock/unlock the @reset_ws as schedule_work()
+ * does its own.
+ *
+ * NOTE: We don't do any reference count tracking because it is not
+ * needed. The lifecycle of the work_struct is tied to the
+ * usb_interface. Before destroying the interface we cancel the
+ * work_struct, so the fact that work_struct is queued and or
+ * running means the interface (and thus, the device) exist and
+ * are referenced.
+ */
+void usb_queue_reset_device(struct usb_interface *iface)
+{
+ schedule_work(&iface->reset_ws);
+}
+EXPORT_SYMBOL_GPL(usb_queue_reset_device);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 6d1048faf08e..de51667dd64d 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -18,6 +18,8 @@
#include "hcd.h" /* for usbcore internals */
#include "usb.h"
+static void cancel_async_set_config(struct usb_device *udev);
+
struct api_context {
struct completion done;
int status;
@@ -139,9 +141,9 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
dr->bRequestType = requesttype;
dr->bRequest = request;
- dr->wValue = cpu_to_le16p(&value);
- dr->wIndex = cpu_to_le16p(&index);
- dr->wLength = cpu_to_le16p(&size);
+ dr->wValue = cpu_to_le16(value);
+ dr->wIndex = cpu_to_le16(index);
+ dr->wLength = cpu_to_le16(size);
/* dbg("usb_control_msg"); */
@@ -1004,6 +1006,34 @@ int usb_clear_halt(struct usb_device *dev, int pipe)
}
EXPORT_SYMBOL_GPL(usb_clear_halt);
+static int create_intf_ep_devs(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_host_interface *alt = intf->cur_altsetting;
+ int i;
+
+ if (intf->ep_devs_created || intf->unregistering)
+ return 0;
+
+ for (i = 0; i < alt->desc.bNumEndpoints; ++i)
+ (void) usb_create_ep_devs(&intf->dev, &alt->endpoint[i], udev);
+ intf->ep_devs_created = 1;
+ return 0;
+}
+
+static void remove_intf_ep_devs(struct usb_interface *intf)
+{
+ struct usb_host_interface *alt = intf->cur_altsetting;
+ int i;
+
+ if (!intf->ep_devs_created)
+ return;
+
+ for (i = 0; i < alt->desc.bNumEndpoints; ++i)
+ usb_remove_ep_devs(&alt->endpoint[i]);
+ intf->ep_devs_created = 0;
+}
+
/**
* usb_disable_endpoint -- Disable an endpoint by address
* @dev: the device whose endpoint is being disabled
@@ -1092,7 +1122,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
dev_dbg(&dev->dev, "unregistering interface %s\n",
dev_name(&interface->dev));
interface->unregistering = 1;
- usb_remove_sysfs_intf_files(interface);
+ remove_intf_ep_devs(interface);
device_del(&interface->dev);
}
@@ -1113,22 +1143,26 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
* usb_enable_endpoint - Enable an endpoint for USB communications
* @dev: the device whose interface is being enabled
* @ep: the endpoint
+ * @reset_toggle: flag to set the endpoint's toggle back to 0
*
- * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
+ * Resets the endpoint toggle if asked, and sets dev->ep_{in,out} pointers.
* For control endpoints, both the input and output sides are handled.
*/
-void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
+void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep,
+ bool reset_toggle)
{
int epnum = usb_endpoint_num(&ep->desc);
int is_out = usb_endpoint_dir_out(&ep->desc);
int is_control = usb_endpoint_xfer_control(&ep->desc);
if (is_out || is_control) {
- usb_settoggle(dev, epnum, 1, 0);
+ if (reset_toggle)
+ usb_settoggle(dev, epnum, 1, 0);
dev->ep_out[epnum] = ep;
}
if (!is_out || is_control) {
- usb_settoggle(dev, epnum, 0, 0);
+ if (reset_toggle)
+ usb_settoggle(dev, epnum, 0, 0);
dev->ep_in[epnum] = ep;
}
ep->enabled = 1;
@@ -1138,17 +1172,18 @@ void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
* usb_enable_interface - Enable all the endpoints for an interface
* @dev: the device whose interface is being enabled
* @intf: pointer to the interface descriptor
+ * @reset_toggles: flag to set the endpoints' toggles back to 0
*
* Enables all the endpoints for the interface's current altsetting.
*/
-static void usb_enable_interface(struct usb_device *dev,
- struct usb_interface *intf)
+void usb_enable_interface(struct usb_device *dev,
+ struct usb_interface *intf, bool reset_toggles)
{
struct usb_host_interface *alt = intf->cur_altsetting;
int i;
for (i = 0; i < alt->desc.bNumEndpoints; ++i)
- usb_enable_endpoint(dev, &alt->endpoint[i]);
+ usb_enable_endpoint(dev, &alt->endpoint[i], reset_toggles);
}
/**
@@ -1235,8 +1270,10 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
*/
/* prevent submissions using previous endpoint settings */
- if (iface->cur_altsetting != alt)
+ if (iface->cur_altsetting != alt) {
+ remove_intf_ep_devs(iface);
usb_remove_sysfs_intf_files(iface);
+ }
usb_disable_interface(dev, iface);
iface->cur_altsetting = alt;
@@ -1271,10 +1308,11 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
* during the SETUP stage - hence EP0 toggles are "don't care" here.
* (Likewise, EP0 never "halts" on well designed devices.)
*/
- usb_enable_interface(dev, iface);
- if (device_is_registered(&iface->dev))
+ usb_enable_interface(dev, iface, true);
+ if (device_is_registered(&iface->dev)) {
usb_create_sysfs_intf_files(iface);
-
+ create_intf_ep_devs(iface);
+ }
return 0;
}
EXPORT_SYMBOL_GPL(usb_set_interface);
@@ -1334,7 +1372,6 @@ int usb_reset_configuration(struct usb_device *dev)
struct usb_interface *intf = config->interface[i];
struct usb_host_interface *alt;
- usb_remove_sysfs_intf_files(intf);
alt = usb_altnum_to_altsetting(intf, 0);
/* No altsetting 0? We'll assume the first altsetting.
@@ -1345,10 +1382,16 @@ int usb_reset_configuration(struct usb_device *dev)
if (!alt)
alt = &intf->altsetting[0];
+ if (alt != intf->cur_altsetting) {
+ remove_intf_ep_devs(intf);
+ usb_remove_sysfs_intf_files(intf);
+ }
intf->cur_altsetting = alt;
- usb_enable_interface(dev, intf);
- if (device_is_registered(&intf->dev))
+ usb_enable_interface(dev, intf, true);
+ if (device_is_registered(&intf->dev)) {
usb_create_sysfs_intf_files(intf);
+ create_intf_ep_devs(intf);
+ }
}
return 0;
}
@@ -1441,6 +1484,46 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
return retval;
}
+
+/*
+ * Internal function to queue a device reset
+ *
+ * This is initialized into the workstruct in 'struct
+ * usb_device->reset_ws' that is launched by
+ * message.c:usb_set_configuration() when initializing each 'struct
+ * usb_interface'.
+ *
+ * It is safe to get the USB device without reference counts because
+ * the life cycle of @iface is bound to the life cycle of @udev. Then,
+ * this function will be ran only if @iface is alive (and before
+ * freeing it any scheduled instances of it will have been cancelled).
+ *
+ * We need to set a flag (usb_dev->reset_running) because when we call
+ * the reset, the interfaces might be unbound. The current interface
+ * cannot try to remove the queued work as it would cause a deadlock
+ * (you cannot remove your work from within your executing
+ * workqueue). This flag lets it know, so that
+ * usb_cancel_queued_reset() doesn't try to do it.
+ *
+ * See usb_queue_reset_device() for more details
+ */
+void __usb_queue_reset_device(struct work_struct *ws)
+{
+ int rc;
+ struct usb_interface *iface =
+ container_of(ws, struct usb_interface, reset_ws);
+ struct usb_device *udev = interface_to_usbdev(iface);
+
+ rc = usb_lock_device_for_reset(udev, iface);
+ if (rc >= 0) {
+ iface->reset_running = 1;
+ usb_reset_device(udev);
+ iface->reset_running = 0;
+ usb_unlock_device(udev);
+ }
+}
+
+
/*
* usb_set_configuration - Makes a particular device setting be current
* @dev: the device whose configuration is being updated
@@ -1560,6 +1643,9 @@ free_interfaces:
if (dev->state != USB_STATE_ADDRESS)
usb_disable_device(dev, 1); /* Skip ep0 */
+ /* Get rid of pending async Set-Config requests for this device */
+ cancel_async_set_config(dev);
+
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
@@ -1604,13 +1690,14 @@ free_interfaces:
alt = &intf->altsetting[0];
intf->cur_altsetting = alt;
- usb_enable_interface(dev, intf);
+ usb_enable_interface(dev, intf, true);
intf->dev.parent = &dev->dev;
intf->dev.driver = NULL;
intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;
intf->dev.groups = usb_interface_groups;
intf->dev.dma_mask = dev->dev.dma_mask;
+ INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
device_initialize(&intf->dev);
mark_quiesced(intf);
dev_set_name(&intf->dev, "%d-%s:%d.%d",
@@ -1641,17 +1728,21 @@ free_interfaces:
dev_name(&intf->dev), ret);
continue;
}
- usb_create_sysfs_intf_files(intf);
+ create_intf_ep_devs(intf);
}
usb_autosuspend_device(dev);
return 0;
}
+static LIST_HEAD(set_config_list);
+static DEFINE_SPINLOCK(set_config_lock);
+
struct set_config_request {
struct usb_device *udev;
int config;
struct work_struct work;
+ struct list_head node;
};
/* Worker routine for usb_driver_set_configuration() */
@@ -1659,14 +1750,35 @@ static void driver_set_config_work(struct work_struct *work)
{
struct set_config_request *req =
container_of(work, struct set_config_request, work);
+ struct usb_device *udev = req->udev;
+
+ usb_lock_device(udev);
+ spin_lock(&set_config_lock);
+ list_del(&req->node);
+ spin_unlock(&set_config_lock);
- usb_lock_device(req->udev);
- usb_set_configuration(req->udev, req->config);
- usb_unlock_device(req->udev);
- usb_put_dev(req->udev);
+ if (req->config >= -1) /* Is req still valid? */
+ usb_set_configuration(udev, req->config);
+ usb_unlock_device(udev);
+ usb_put_dev(udev);
kfree(req);
}
+/* Cancel pending Set-Config requests for a device whose configuration
+ * was just changed
+ */
+static void cancel_async_set_config(struct usb_device *udev)
+{
+ struct set_config_request *req;
+
+ spin_lock(&set_config_lock);
+ list_for_each_entry(req, &set_config_list, node) {
+ if (req->udev == udev)
+ req->config = -999; /* Mark as cancelled */
+ }
+ spin_unlock(&set_config_lock);
+}
+
/**
* usb_driver_set_configuration - Provide a way for drivers to change device configurations
* @udev: the device whose configuration is being updated
@@ -1698,6 +1810,10 @@ int usb_driver_set_configuration(struct usb_device *udev, int config)
req->config = config;
INIT_WORK(&req->work, driver_set_config_work);
+ spin_lock(&set_config_lock);
+ list_add(&req->node, &set_config_list);
+ spin_unlock(&set_config_lock);
+
usb_get_dev(udev);
schedule_work(&req->work);
return 0;
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 4fb65fdc9dc3..4cc2456ef3be 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -359,19 +359,19 @@ set_level(struct device *dev, struct device_attribute *attr,
strncmp(buf, on_string, len) == 0) {
udev->autosuspend_disabled = 1;
udev->autoresume_disabled = 0;
- rc = usb_external_resume_device(udev);
+ rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
} else if (len == sizeof auto_string - 1 &&
strncmp(buf, auto_string, len) == 0) {
udev->autosuspend_disabled = 0;
udev->autoresume_disabled = 0;
- rc = usb_external_resume_device(udev);
+ rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
} else if (len == sizeof suspend_string - 1 &&
strncmp(buf, suspend_string, len) == 0) {
udev->autosuspend_disabled = 0;
udev->autoresume_disabled = 1;
- rc = usb_external_suspend_device(udev, PMSG_SUSPEND);
+ rc = usb_external_suspend_device(udev, PMSG_USER_SUSPEND);
} else
rc = -EINVAL;
@@ -629,9 +629,6 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
struct device *dev = &udev->dev;
int retval;
- /* Unforunately these attributes cannot be created before
- * the uevent is broadcast.
- */
retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
if (retval)
goto error;
@@ -643,11 +640,7 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
retval = add_power_attributes(dev);
if (retval)
goto error;
-
- retval = usb_create_ep_files(dev, &udev->ep0, udev);
- if (retval)
- goto error;
- return 0;
+ return retval;
error:
usb_remove_sysfs_dev_files(udev);
return retval;
@@ -657,7 +650,6 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
{
struct device *dev = &udev->dev;
- usb_remove_ep_files(&udev->ep0);
remove_power_attributes(dev);
remove_persist_attributes(dev);
device_remove_bin_file(dev, &dev_bin_attr_descriptors);
@@ -812,28 +804,6 @@ struct attribute_group *usb_interface_groups[] = {
NULL
};
-static inline void usb_create_intf_ep_files(struct usb_interface *intf,
- struct usb_device *udev)
-{
- struct usb_host_interface *iface_desc;
- int i;
-
- iface_desc = intf->cur_altsetting;
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
- usb_create_ep_files(&intf->dev, &iface_desc->endpoint[i],
- udev);
-}
-
-static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
-{
- struct usb_host_interface *iface_desc;
- int i;
-
- iface_desc = intf->cur_altsetting;
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
- usb_remove_ep_files(&iface_desc->endpoint[i]);
-}
-
int usb_create_sysfs_intf_files(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
@@ -843,26 +813,19 @@ int usb_create_sysfs_intf_files(struct usb_interface *intf)
if (intf->sysfs_files_created || intf->unregistering)
return 0;
- /* The interface string may be present in some altsettings
- * and missing in others. Hence its attribute cannot be created
- * before the uevent is broadcast.
- */
if (alt->string == NULL)
alt->string = usb_cache_string(udev, alt->desc.iInterface);
if (alt->string)
retval = device_create_file(&intf->dev, &dev_attr_interface);
- usb_create_intf_ep_files(intf, udev);
intf->sysfs_files_created = 1;
return 0;
}
void usb_remove_sysfs_intf_files(struct usb_interface *intf)
{
- struct device *dev = &intf->dev;
-
if (!intf->sysfs_files_created)
return;
- usb_remove_intf_ep_files(intf);
- device_remove_file(dev, &dev_attr_interface);
+
+ device_remove_file(&intf->dev, &dev_attr_interface);
intf->sysfs_files_created = 0;
}
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 1f68af9db3f7..58bc5e3c2560 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -10,7 +10,6 @@
#define to_urb(d) container_of(d, struct urb, kref)
-static DEFINE_SPINLOCK(usb_reject_lock);
static void urb_destroy(struct kref *kref)
{
@@ -131,9 +130,7 @@ void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)
urb->anchor = anchor;
if (unlikely(anchor->poisoned)) {
- spin_lock(&usb_reject_lock);
- urb->reject++;
- spin_unlock(&usb_reject_lock);
+ atomic_inc(&urb->reject);
}
spin_unlock_irqrestore(&anchor->lock, flags);
@@ -565,16 +562,12 @@ void usb_kill_urb(struct urb *urb)
might_sleep();
if (!(urb && urb->dev && urb->ep))
return;
- spin_lock_irq(&usb_reject_lock);
- ++urb->reject;
- spin_unlock_irq(&usb_reject_lock);
+ atomic_inc(&urb->reject);
usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
- spin_lock_irq(&usb_reject_lock);
- --urb->reject;
- spin_unlock_irq(&usb_reject_lock);
+ atomic_dec(&urb->reject);
}
EXPORT_SYMBOL_GPL(usb_kill_urb);
@@ -606,9 +599,7 @@ void usb_poison_urb(struct urb *urb)
might_sleep();
if (!(urb && urb->dev && urb->ep))
return;
- spin_lock_irq(&usb_reject_lock);
- ++urb->reject;
- spin_unlock_irq(&usb_reject_lock);
+ atomic_inc(&urb->reject);
usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
@@ -617,14 +608,10 @@ EXPORT_SYMBOL_GPL(usb_poison_urb);
void usb_unpoison_urb(struct urb *urb)
{
- unsigned long flags;
-
if (!urb)
return;
- spin_lock_irqsave(&usb_reject_lock, flags);
- --urb->reject;
- spin_unlock_irqrestore(&usb_reject_lock, flags);
+ atomic_dec(&urb->reject);
}
EXPORT_SYMBOL_GPL(usb_unpoison_urb);
@@ -692,6 +679,26 @@ void usb_poison_anchored_urbs(struct usb_anchor *anchor)
EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs);
/**
+ * usb_unpoison_anchored_urbs - let an anchor be used successfully again
+ * @anchor: anchor the requests are bound to
+ *
+ * Reverses the effect of usb_poison_anchored_urbs
+ * the anchor can be used normally after it returns
+ */
+void usb_unpoison_anchored_urbs(struct usb_anchor *anchor)
+{
+ unsigned long flags;
+ struct urb *lazarus;
+
+ spin_lock_irqsave(&anchor->lock, flags);
+ list_for_each_entry(lazarus, &anchor->urb_list, anchor_list) {
+ usb_unpoison_urb(lazarus);
+ }
+ anchor->poisoned = 0;
+ spin_unlock_irqrestore(&anchor->lock, flags);
+}
+EXPORT_SYMBOL_GPL(usb_unpoison_anchored_urbs);
+/**
* usb_unlink_anchored_urbs - asynchronously cancel transfer requests en masse
* @anchor: anchor the requests are bound to
*
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 399e15fc5052..dcfc072630c1 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -253,7 +253,7 @@ static int usb_dev_prepare(struct device *dev)
static void usb_dev_complete(struct device *dev)
{
/* Currently used only for rebinding interfaces */
- usb_resume(dev); /* Implement eventually? */
+ usb_resume(dev, PMSG_RESUME); /* Message event is meaningless */
}
static int usb_dev_suspend(struct device *dev)
@@ -263,7 +263,7 @@ static int usb_dev_suspend(struct device *dev)
static int usb_dev_resume(struct device *dev)
{
- return usb_resume(dev);
+ return usb_resume(dev, PMSG_RESUME);
}
static int usb_dev_freeze(struct device *dev)
@@ -273,7 +273,7 @@ static int usb_dev_freeze(struct device *dev)
static int usb_dev_thaw(struct device *dev)
{
- return usb_resume(dev);
+ return usb_resume(dev, PMSG_THAW);
}
static int usb_dev_poweroff(struct device *dev)
@@ -283,7 +283,7 @@ static int usb_dev_poweroff(struct device *dev)
static int usb_dev_restore(struct device *dev)
{
- return usb_resume(dev);
+ return usb_resume(dev, PMSG_RESTORE);
}
static struct dev_pm_ops usb_device_pm_ops = {
@@ -362,7 +362,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
/* ep0 maxpacket comes later, from device descriptor */
- usb_enable_endpoint(dev, &dev->ep0);
+ usb_enable_endpoint(dev, &dev->ep0, true);
dev->can_submit = 1;
/* Save readable and stable topology id, distinguishing devices
@@ -402,6 +402,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
#ifdef CONFIG_PM
mutex_init(&dev->pm_mutex);
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
+ INIT_WORK(&dev->autoresume, usb_autoresume_work);
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
dev->connect_time = jiffies;
dev->active_duration = -jiffies;
@@ -513,10 +514,7 @@ EXPORT_SYMBOL_GPL(usb_put_intf);
* disconnect; in some drivers (such as usb-storage) the disconnect()
* or suspend() method will block waiting for a device reset to complete.
*
- * Returns a negative error code for failure, otherwise 1 or 0 to indicate
- * that the device will or will not have to be unlocked. (0 can be
- * returned when an interface is given and is BINDING, because in that
- * case the driver already owns the device lock.)
+ * Returns a negative error code for failure, otherwise 0.
*/
int usb_lock_device_for_reset(struct usb_device *udev,
const struct usb_interface *iface)
@@ -527,16 +525,9 @@ int usb_lock_device_for_reset(struct usb_device *udev,
return -ENODEV;
if (udev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
- if (iface) {
- switch (iface->condition) {
- case USB_INTERFACE_BINDING:
- return 0;
- case USB_INTERFACE_BOUND:
- break;
- default:
- return -EINTR;
- }
- }
+ if (iface && (iface->condition == USB_INTERFACE_UNBINDING ||
+ iface->condition == USB_INTERFACE_UNBOUND))
+ return -EINTR;
while (usb_trylock_device(udev) != 0) {
@@ -550,10 +541,11 @@ int usb_lock_device_for_reset(struct usb_device *udev,
return -ENODEV;
if (udev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
- if (iface && iface->condition != USB_INTERFACE_BOUND)
+ if (iface && (iface->condition == USB_INTERFACE_UNBINDING ||
+ iface->condition == USB_INTERFACE_UNBOUND))
return -EINTR;
}
- return 1;
+ return 0;
}
EXPORT_SYMBOL_GPL(usb_lock_device_for_reset);
@@ -962,8 +954,12 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
}
EXPORT_SYMBOL_GPL(usb_buffer_unmap_sg);
-/* format to disable USB on kernel command line is: nousb */
-__module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444);
+/* To disable USB, kernel command line is 'nousb' not 'usbcore.nousb' */
+#ifdef MODULE
+module_param(nousb, bool, 0444);
+#else
+core_param(nousb, nousb, bool, 0444);
+#endif
/*
* for external read access to <nousb>
@@ -975,6 +971,37 @@ int usb_disabled(void)
EXPORT_SYMBOL_GPL(usb_disabled);
/*
+ * Notifications of device and interface registration
+ */
+static int usb_bus_notify(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct device *dev = data;
+
+ switch (action) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ if (dev->type == &usb_device_type)
+ (void) usb_create_sysfs_dev_files(to_usb_device(dev));
+ else if (dev->type == &usb_if_device_type)
+ (void) usb_create_sysfs_intf_files(
+ to_usb_interface(dev));
+ break;
+
+ case BUS_NOTIFY_DEL_DEVICE:
+ if (dev->type == &usb_device_type)
+ usb_remove_sysfs_dev_files(to_usb_device(dev));
+ else if (dev->type == &usb_if_device_type)
+ usb_remove_sysfs_intf_files(to_usb_interface(dev));
+ break;
+ }
+ return 0;
+}
+
+static struct notifier_block usb_bus_nb = {
+ .notifier_call = usb_bus_notify,
+};
+
+/*
* Init
*/
static int __init usb_init(void)
@@ -991,6 +1018,9 @@ static int __init usb_init(void)
retval = bus_register(&usb_bus_type);
if (retval)
goto bus_register_failed;
+ retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);
+ if (retval)
+ goto bus_notifier_failed;
retval = usb_host_init();
if (retval)
goto host_init_failed;
@@ -1025,6 +1055,8 @@ driver_register_failed:
major_init_failed:
usb_host_cleanup();
host_init_failed:
+ bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
+bus_notifier_failed:
bus_unregister(&usb_bus_type);
bus_register_failed:
ksuspend_usb_cleanup();
@@ -1048,6 +1080,7 @@ static void __exit usb_exit(void)
usb_devio_cleanup();
usb_hub_cleanup();
usb_host_cleanup();
+ bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
bus_unregister(&usb_bus_type);
ksuspend_usb_cleanup();
}
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 9a1a45ac3add..386177867a8a 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -1,16 +1,20 @@
+#include <linux/pm.h>
+
/* Functions local to drivers/usb/core/ */
extern int usb_create_sysfs_dev_files(struct usb_device *dev);
extern void usb_remove_sysfs_dev_files(struct usb_device *dev);
extern int usb_create_sysfs_intf_files(struct usb_interface *intf);
extern void usb_remove_sysfs_intf_files(struct usb_interface *intf);
-extern int usb_create_ep_files(struct device *parent,
+extern int usb_create_ep_devs(struct device *parent,
struct usb_host_endpoint *endpoint,
struct usb_device *udev);
-extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
+extern void usb_remove_ep_devs(struct usb_host_endpoint *endpoint);
extern void usb_enable_endpoint(struct usb_device *dev,
- struct usb_host_endpoint *ep);
+ struct usb_host_endpoint *ep, bool reset_toggle);
+extern void usb_enable_interface(struct usb_device *dev,
+ struct usb_interface *intf, bool reset_toggles);
extern void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr);
extern void usb_disable_interface(struct usb_device *dev,
struct usb_interface *intf);
@@ -42,14 +46,16 @@ extern void usb_host_cleanup(void);
#ifdef CONFIG_PM
extern int usb_suspend(struct device *dev, pm_message_t msg);
-extern int usb_resume(struct device *dev);
+extern int usb_resume(struct device *dev, pm_message_t msg);
extern void usb_autosuspend_work(struct work_struct *work);
-extern int usb_port_suspend(struct usb_device *dev);
-extern int usb_port_resume(struct usb_device *dev);
+extern void usb_autoresume_work(struct work_struct *work);
+extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
+extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);
extern int usb_external_suspend_device(struct usb_device *udev,
pm_message_t msg);
-extern int usb_external_resume_device(struct usb_device *udev);
+extern int usb_external_resume_device(struct usb_device *udev,
+ pm_message_t msg);
static inline void usb_pm_lock(struct usb_device *udev)
{
@@ -63,12 +69,12 @@ static inline void usb_pm_unlock(struct usb_device *udev)
#else
-static inline int usb_port_suspend(struct usb_device *udev)
+static inline int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
{
return 0;
}
-static inline int usb_port_resume(struct usb_device *udev)
+static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
{
return 0;
}
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index dd4cd5a51370..3219d137340a 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -297,13 +297,34 @@ config USB_S3C2410_DEBUG
# musb builds in ../musb along with host support
config USB_GADGET_MUSB_HDRC
- boolean "Inventra HDRC USB Peripheral (TI, ...)"
+ boolean "Inventra HDRC USB Peripheral (TI, ADI, ...)"
depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
select USB_GADGET_DUALSPEED
select USB_GADGET_SELECTED
help
This OTG-capable silicon IP is used in dual designs including
- the TI DaVinci, OMAP 243x, OMAP 343x, and TUSB 6010.
+ the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin
+
+config USB_GADGET_IMX
+ boolean "Freescale IMX USB Peripheral Controller"
+ depends on ARCH_MX1
+ help
+ Freescale's IMX series include an integrated full speed
+ USB 1.1 device controller. The controller in the IMX series
+ is register-compatible.
+
+ It has Six fixed-function endpoints, as well as endpoint
+ zero (for control transfers).
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "imx_udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_IMX
+ tristate
+ depends on USB_GADGET_IMX
+ default USB_GADGET
+ select USB_GADGET_SELECTED
config USB_GADGET_M66592
boolean "Renesas M66592 USB Peripheral Controller"
@@ -377,6 +398,24 @@ config USB_FSL_QE
default USB_GADGET
select USB_GADGET_SELECTED
+config USB_GADGET_CI13XXX
+ boolean "MIPS USB CI13xxx"
+ depends on PCI
+ select USB_GADGET_DUALSPEED
+ help
+ MIPS USB IP core family device controller
+ Currently it only supports IP part number CI13412
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "ci13xxx_udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_CI13XXX
+ tristate
+ depends on USB_GADGET_CI13XXX
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_NET2280
boolean "NetChip 228x"
depends on PCI
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index bd4041b47dce..39a51d746cb7 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_USB_NET2280) += net2280.o
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o
obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o
+obj-$(CONFIG_USB_IMX) += imx_udc.o
obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
+obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o
#
# USB gadget drivers
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
new file mode 100644
index 000000000000..bebf911c7e5f
--- /dev/null
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -0,0 +1,2830 @@
+/*
+ * ci13xxx_udc.c - MIPS USB IP core family device controller
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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.
+ */
+
+/*
+ * Description: MIPS USB IP core family device controller
+ * Currently it only supports IP part number CI13412
+ *
+ * This driver is composed of several blocks:
+ * - HW: hardware interface
+ * - DBG: debug facilities (optional)
+ * - UTIL: utilities
+ * - ISR: interrupts handling
+ * - ENDPT: endpoint operations (Gadget API)
+ * - GADGET: gadget operations (Gadget API)
+ * - BUS: bus glue code, bus abstraction layer
+ * - PCI: PCI core interface and PCI resources (interrupts, memory...)
+ *
+ * Compile Options
+ * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
+ * - STALL_IN: non-empty bulk-in pipes cannot be halted
+ * if defined mass storage compliance succeeds but with warnings
+ * => case 4: Hi > Dn
+ * => case 5: Hi > Di
+ * => case 8: Hi <> Do
+ * if undefined usbtest 13 fails
+ * - TRACE: enable function tracing (depends on DEBUG)
+ *
+ * Main Features
+ * - Chapter 9 & Mass Storage Compliance with Gadget File Storage
+ * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined)
+ * - Normal & LPM support
+ *
+ * USBTEST Report
+ * - OK: 0-12, 13 (STALL_IN defined) & 14
+ * - Not Supported: 15 & 16 (ISO)
+ *
+ * TODO List
+ * - OTG
+ * - Isochronous & Interrupt Traffic
+ * - Handle requests which spawns into several TDs
+ * - GET_STATUS(device) - always reports 0
+ * - Gadget API (majority of optional features)
+ * - Suspend & Remote Wakeup
+ */
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "ci13xxx_udc.h"
+
+
+/******************************************************************************
+ * DEFINE
+ *****************************************************************************/
+/* ctrl register bank access */
+static DEFINE_SPINLOCK(udc_lock);
+
+/* driver name */
+#define UDC_DRIVER_NAME "ci13xxx_udc"
+
+/* control endpoint description */
+static const struct usb_endpoint_descriptor
+ctrl_endpt_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX),
+};
+
+/* UDC descriptor */
+static struct ci13xxx *_udc;
+
+/* Interrupt statistics */
+#define ISR_MASK 0x1F
+static struct {
+ u32 test;
+ u32 ui;
+ u32 uei;
+ u32 pci;
+ u32 uri;
+ u32 sli;
+ u32 none;
+ struct {
+ u32 cnt;
+ u32 buf[ISR_MASK+1];
+ u32 idx;
+ } hndl;
+} isr_statistics;
+
+/**
+ * ffs_nr: find first (least significant) bit set
+ * @x: the word to search
+ *
+ * This function returns bit number (instead of position)
+ */
+static int ffs_nr(u32 x)
+{
+ int n = ffs(x);
+
+ return n ? n-1 : 32;
+}
+
+/******************************************************************************
+ * HW block
+ *****************************************************************************/
+/* register bank descriptor */
+static struct {
+ unsigned lpm; /* is LPM? */
+ void __iomem *abs; /* bus map offset */
+ void __iomem *cap; /* bus map offset + CAP offset + CAP data */
+ size_t size; /* bank size */
+} hw_bank;
+
+/* UDC register map */
+#define ABS_CAPLENGTH (0x100UL)
+#define ABS_HCCPARAMS (0x108UL)
+#define ABS_DCCPARAMS (0x124UL)
+#define ABS_TESTMODE (hw_bank.lpm ? 0x0FCUL : 0x138UL)
+/* offset to CAPLENTGH (addr + data) */
+#define CAP_USBCMD (0x000UL)
+#define CAP_USBSTS (0x004UL)
+#define CAP_USBINTR (0x008UL)
+#define CAP_DEVICEADDR (0x014UL)
+#define CAP_ENDPTLISTADDR (0x018UL)
+#define CAP_PORTSC (0x044UL)
+#define CAP_DEVLC (0x0B4UL)
+#define CAP_USBMODE (hw_bank.lpm ? 0x0C8UL : 0x068UL)
+#define CAP_ENDPTSETUPSTAT (hw_bank.lpm ? 0x0D8UL : 0x06CUL)
+#define CAP_ENDPTPRIME (hw_bank.lpm ? 0x0DCUL : 0x070UL)
+#define CAP_ENDPTFLUSH (hw_bank.lpm ? 0x0E0UL : 0x074UL)
+#define CAP_ENDPTSTAT (hw_bank.lpm ? 0x0E4UL : 0x078UL)
+#define CAP_ENDPTCOMPLETE (hw_bank.lpm ? 0x0E8UL : 0x07CUL)
+#define CAP_ENDPTCTRL (hw_bank.lpm ? 0x0ECUL : 0x080UL)
+#define CAP_LAST (hw_bank.lpm ? 0x12CUL : 0x0C0UL)
+
+/* maximum number of enpoints: valid only after hw_device_reset() */
+static unsigned hw_ep_max;
+
+/**
+ * hw_ep_bit: calculates the bit number
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns bit number
+ */
+static inline int hw_ep_bit(int num, int dir)
+{
+ return num + (dir ? 16 : 0);
+}
+
+/**
+ * hw_aread: reads from register bitfield
+ * @addr: address relative to bus map
+ * @mask: bitfield mask
+ *
+ * This function returns register bitfield data
+ */
+static u32 hw_aread(u32 addr, u32 mask)
+{
+ return ioread32(addr + hw_bank.abs) & mask;
+}
+
+/**
+ * hw_awrite: writes to register bitfield
+ * @addr: address relative to bus map
+ * @mask: bitfield mask
+ * @data: new data
+ */
+static void hw_awrite(u32 addr, u32 mask, u32 data)
+{
+ iowrite32(hw_aread(addr, ~mask) | (data & mask),
+ addr + hw_bank.abs);
+}
+
+/**
+ * hw_cread: reads from register bitfield
+ * @addr: address relative to CAP offset plus content
+ * @mask: bitfield mask
+ *
+ * This function returns register bitfield data
+ */
+static u32 hw_cread(u32 addr, u32 mask)
+{
+ return ioread32(addr + hw_bank.cap) & mask;
+}
+
+/**
+ * hw_cwrite: writes to register bitfield
+ * @addr: address relative to CAP offset plus content
+ * @mask: bitfield mask
+ * @data: new data
+ */
+static void hw_cwrite(u32 addr, u32 mask, u32 data)
+{
+ iowrite32(hw_cread(addr, ~mask) | (data & mask),
+ addr + hw_bank.cap);
+}
+
+/**
+ * hw_ctest_and_clear: tests & clears register bitfield
+ * @addr: address relative to CAP offset plus content
+ * @mask: bitfield mask
+ *
+ * This function returns register bitfield data
+ */
+static u32 hw_ctest_and_clear(u32 addr, u32 mask)
+{
+ u32 reg = hw_cread(addr, mask);
+
+ iowrite32(reg, addr + hw_bank.cap);
+ return reg;
+}
+
+/**
+ * hw_ctest_and_write: tests & writes register bitfield
+ * @addr: address relative to CAP offset plus content
+ * @mask: bitfield mask
+ * @data: new data
+ *
+ * This function returns register bitfield data
+ */
+static u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data)
+{
+ u32 reg = hw_cread(addr, ~0);
+
+ iowrite32((reg & ~mask) | (data & mask), addr + hw_bank.cap);
+ return (reg & mask) >> ffs_nr(mask);
+}
+
+/**
+ * hw_device_reset: resets chip (execute without interruption)
+ * @base: register base address
+ *
+ * This function returns an error code
+ */
+static int hw_device_reset(void __iomem *base)
+{
+ u32 reg;
+
+ /* bank is a module variable */
+ hw_bank.abs = base;
+
+ hw_bank.cap = hw_bank.abs;
+ hw_bank.cap += ABS_CAPLENGTH;
+ hw_bank.cap += ioread8(hw_bank.cap);
+
+ reg = hw_aread(ABS_HCCPARAMS, HCCPARAMS_LEN) >> ffs_nr(HCCPARAMS_LEN);
+ hw_bank.lpm = reg;
+ hw_bank.size = hw_bank.cap - hw_bank.abs;
+ hw_bank.size += CAP_LAST;
+ hw_bank.size /= sizeof(u32);
+
+ /* should flush & stop before reset */
+ hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0);
+ hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
+
+ hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST);
+ while (hw_cread(CAP_USBCMD, USBCMD_RST))
+ udelay(10); /* not RTOS friendly */
+
+ /* USBMODE should be configured step by step */
+ hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
+ hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE);
+ hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); /* HW >= 2.3 */
+
+ if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) {
+ pr_err("cannot enter in device mode");
+ pr_err("lpm = %i", hw_bank.lpm);
+ return -ENODEV;
+ }
+
+ reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN);
+ if (reg == 0 || reg > ENDPT_MAX)
+ return -ENODEV;
+
+ hw_ep_max = reg; /* cache hw ENDPT_MAX */
+
+ /* setup lock mode ? */
+
+ /* ENDPTSETUPSTAT is '0' by default */
+
+ /* HCSPARAMS.bf.ppc SHOULD BE zero for device */
+
+ return 0;
+}
+
+/**
+ * hw_device_state: enables/disables interrupts & starts/stops device (execute
+ * without interruption)
+ * @dma: 0 => disable, !0 => enable and set dma engine
+ *
+ * This function returns an error code
+ */
+static int hw_device_state(u32 dma)
+{
+ if (dma) {
+ hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
+ /* interrupt, error, port change, reset, sleep/suspend */
+ hw_cwrite(CAP_USBINTR, ~0,
+ USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
+ hw_cwrite(CAP_USBCMD, USBCMD_RS, USBCMD_RS);
+ } else {
+ hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
+ hw_cwrite(CAP_USBINTR, ~0, 0);
+ }
+ return 0;
+}
+
+/**
+ * hw_ep_flush: flush endpoint fifo (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns an error code
+ */
+static int hw_ep_flush(int num, int dir)
+{
+ int n = hw_ep_bit(num, dir);
+
+ do {
+ /* flush any pending transfer */
+ hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n));
+ while (hw_cread(CAP_ENDPTFLUSH, BIT(n)))
+ cpu_relax();
+ } while (hw_cread(CAP_ENDPTSTAT, BIT(n)));
+
+ return 0;
+}
+
+/**
+ * hw_ep_disable: disables endpoint (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns an error code
+ */
+static int hw_ep_disable(int num, int dir)
+{
+ hw_ep_flush(num, dir);
+ hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32),
+ dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0);
+ return 0;
+}
+
+/**
+ * hw_ep_enable: enables endpoint (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ * @type: endpoint type
+ *
+ * This function returns an error code
+ */
+static int hw_ep_enable(int num, int dir, int type)
+{
+ u32 mask, data;
+
+ if (dir) {
+ mask = ENDPTCTRL_TXT; /* type */
+ data = type << ffs_nr(mask);
+
+ mask |= ENDPTCTRL_TXS; /* unstall */
+ mask |= ENDPTCTRL_TXR; /* reset data toggle */
+ data |= ENDPTCTRL_TXR;
+ mask |= ENDPTCTRL_TXE; /* enable */
+ data |= ENDPTCTRL_TXE;
+ } else {
+ mask = ENDPTCTRL_RXT; /* type */
+ data = type << ffs_nr(mask);
+
+ mask |= ENDPTCTRL_RXS; /* unstall */
+ mask |= ENDPTCTRL_RXR; /* reset data toggle */
+ data |= ENDPTCTRL_RXR;
+ mask |= ENDPTCTRL_RXE; /* enable */
+ data |= ENDPTCTRL_RXE;
+ }
+ hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), mask, data);
+ return 0;
+}
+
+/**
+ * hw_ep_get_halt: return endpoint halt status
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns 1 if endpoint halted
+ */
+static int hw_ep_get_halt(int num, int dir)
+{
+ u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+
+ return hw_cread(CAP_ENDPTCTRL + num * sizeof(u32), mask) ? 1 : 0;
+}
+
+/**
+ * hw_ep_is_primed: test if endpoint is primed (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns true if endpoint primed
+ */
+static int hw_ep_is_primed(int num, int dir)
+{
+ u32 reg = hw_cread(CAP_ENDPTPRIME, ~0) | hw_cread(CAP_ENDPTSTAT, ~0);
+
+ return test_bit(hw_ep_bit(num, dir), (void *)&reg);
+}
+
+/**
+ * hw_test_and_clear_setup_status: test & clear setup status (execute without
+ * interruption)
+ * @n: bit number (endpoint)
+ *
+ * This function returns setup status
+ */
+static int hw_test_and_clear_setup_status(int n)
+{
+ return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n));
+}
+
+/**
+ * hw_ep_prime: primes endpoint (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ * @is_ctrl: true if control endpoint
+ *
+ * This function returns an error code
+ */
+static int hw_ep_prime(int num, int dir, int is_ctrl)
+{
+ int n = hw_ep_bit(num, dir);
+
+ /* the caller should flush first */
+ if (hw_ep_is_primed(num, dir))
+ return -EBUSY;
+
+ if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
+ return -EAGAIN;
+
+ hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n));
+
+ while (hw_cread(CAP_ENDPTPRIME, BIT(n)))
+ cpu_relax();
+ if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
+ return -EAGAIN;
+
+ /* status shoult be tested according with manual but it doesn't work */
+ return 0;
+}
+
+/**
+ * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute
+ * without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ * @value: true => stall, false => unstall
+ *
+ * This function returns an error code
+ */
+static int hw_ep_set_halt(int num, int dir, int value)
+{
+ if (value != 0 && value != 1)
+ return -EINVAL;
+
+ do {
+ u32 addr = CAP_ENDPTCTRL + num * sizeof(u32);
+ u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+ u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR;
+
+ /* data toggle - reserved for EP0 but it's in ESS */
+ hw_cwrite(addr, mask_xs|mask_xr, value ? mask_xs : mask_xr);
+
+ } while (value != hw_ep_get_halt(num, dir));
+
+ return 0;
+}
+
+/**
+ * hw_intr_clear: disables interrupt & clears interrupt status (execute without
+ * interruption)
+ * @n: interrupt bit
+ *
+ * This function returns an error code
+ */
+static int hw_intr_clear(int n)
+{
+ if (n >= REG_BITS)
+ return -EINVAL;
+
+ hw_cwrite(CAP_USBINTR, BIT(n), 0);
+ hw_cwrite(CAP_USBSTS, BIT(n), BIT(n));
+ return 0;
+}
+
+/**
+ * hw_intr_force: enables interrupt & forces interrupt status (execute without
+ * interruption)
+ * @n: interrupt bit
+ *
+ * This function returns an error code
+ */
+static int hw_intr_force(int n)
+{
+ if (n >= REG_BITS)
+ return -EINVAL;
+
+ hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
+ hw_cwrite(CAP_USBINTR, BIT(n), BIT(n));
+ hw_cwrite(CAP_USBSTS, BIT(n), BIT(n));
+ hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, 0);
+ return 0;
+}
+
+/**
+ * hw_is_port_high_speed: test if port is high speed
+ *
+ * This function returns true if high speed port
+ */
+static int hw_port_is_high_speed(void)
+{
+ return hw_bank.lpm ? hw_cread(CAP_DEVLC, DEVLC_PSPD) :
+ hw_cread(CAP_PORTSC, PORTSC_HSP);
+}
+
+/**
+ * hw_port_test_get: reads port test mode value
+ *
+ * This function returns port test mode value
+ */
+static u8 hw_port_test_get(void)
+{
+ return hw_cread(CAP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
+}
+
+/**
+ * hw_port_test_set: writes port test mode (execute without interruption)
+ * @mode: new value
+ *
+ * This function returns an error code
+ */
+static int hw_port_test_set(u8 mode)
+{
+ const u8 TEST_MODE_MAX = 7;
+
+ if (mode > TEST_MODE_MAX)
+ return -EINVAL;
+
+ hw_cwrite(CAP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
+ return 0;
+}
+
+/**
+ * hw_read_intr_enable: returns interrupt enable register
+ *
+ * This function returns register data
+ */
+static u32 hw_read_intr_enable(void)
+{
+ return hw_cread(CAP_USBINTR, ~0);
+}
+
+/**
+ * hw_read_intr_status: returns interrupt status register
+ *
+ * This function returns register data
+ */
+static u32 hw_read_intr_status(void)
+{
+ return hw_cread(CAP_USBSTS, ~0);
+}
+
+/**
+ * hw_register_read: reads all device registers (execute without interruption)
+ * @buf: destination buffer
+ * @size: buffer size
+ *
+ * This function returns number of registers read
+ */
+static size_t hw_register_read(u32 *buf, size_t size)
+{
+ unsigned i;
+
+ if (size > hw_bank.size)
+ size = hw_bank.size;
+
+ for (i = 0; i < size; i++)
+ buf[i] = hw_aread(i * sizeof(u32), ~0);
+
+ return size;
+}
+
+/**
+ * hw_register_write: writes to register
+ * @addr: register address
+ * @data: register value
+ *
+ * This function returns an error code
+ */
+static int hw_register_write(u16 addr, u32 data)
+{
+ /* align */
+ addr /= sizeof(u32);
+
+ if (addr >= hw_bank.size)
+ return -EINVAL;
+
+ /* align */
+ addr *= sizeof(u32);
+
+ hw_awrite(addr, ~0, data);
+ return 0;
+}
+
+/**
+ * hw_test_and_clear_complete: test & clear complete status (execute without
+ * interruption)
+ * @n: bit number (endpoint)
+ *
+ * This function returns complete status
+ */
+static int hw_test_and_clear_complete(int n)
+{
+ return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n));
+}
+
+/**
+ * hw_test_and_clear_intr_active: test & clear active interrupts (execute
+ * without interruption)
+ *
+ * This function returns active interrutps
+ */
+static u32 hw_test_and_clear_intr_active(void)
+{
+ u32 reg = hw_read_intr_status() & hw_read_intr_enable();
+
+ hw_cwrite(CAP_USBSTS, ~0, reg);
+ return reg;
+}
+
+/**
+ * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
+ * interruption)
+ *
+ * This function returns guard value
+ */
+static int hw_test_and_clear_setup_guard(void)
+{
+ return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, 0);
+}
+
+/**
+ * hw_test_and_set_setup_guard: test & set setup guard (execute without
+ * interruption)
+ *
+ * This function returns guard value
+ */
+static int hw_test_and_set_setup_guard(void)
+{
+ return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, USBCMD_SUTW);
+}
+
+/**
+ * hw_usb_set_address: configures USB address (execute without interruption)
+ * @value: new USB address
+ *
+ * This function returns an error code
+ */
+static int hw_usb_set_address(u8 value)
+{
+ /* advance */
+ hw_cwrite(CAP_DEVICEADDR, DEVICEADDR_USBADR | DEVICEADDR_USBADRA,
+ value << ffs_nr(DEVICEADDR_USBADR) | DEVICEADDR_USBADRA);
+ return 0;
+}
+
+/**
+ * hw_usb_reset: restart device after a bus reset (execute without
+ * interruption)
+ *
+ * This function returns an error code
+ */
+static int hw_usb_reset(void)
+{
+ hw_usb_set_address(0);
+
+ /* ESS flushes only at end?!? */
+ hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); /* flush all EPs */
+
+ /* clear setup token semaphores */
+ hw_cwrite(CAP_ENDPTSETUPSTAT, 0, 0); /* writes its content */
+
+ /* clear complete status */
+ hw_cwrite(CAP_ENDPTCOMPLETE, 0, 0); /* writes its content */
+
+ /* wait until all bits cleared */
+ while (hw_cread(CAP_ENDPTPRIME, ~0))
+ udelay(10); /* not RTOS friendly */
+
+ /* reset all endpoints ? */
+
+ /* reset internal status and wait for further instructions
+ no need to verify the port reset status (ESS does it) */
+
+ return 0;
+}
+
+/******************************************************************************
+ * DBG block
+ *****************************************************************************/
+/**
+ * show_device: prints information about device capabilities and status
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_device(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ struct usb_gadget *gadget = &udc->gadget;
+ int n = 0;
+
+ dbg_trace("[%s] %p\n", __func__, buf);
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n",
+ gadget->speed);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n",
+ gadget->is_dualspeed);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n",
+ gadget->is_otg);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n",
+ gadget->is_a_peripheral);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n",
+ gadget->b_hnp_enable);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n",
+ gadget->a_hnp_support);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
+ gadget->a_alt_hnp_support);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n",
+ (gadget->name ? gadget->name : ""));
+
+ return n;
+}
+static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
+
+/**
+ * show_driver: prints information about attached gadget (if any)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ struct usb_gadget_driver *driver = udc->driver;
+ int n = 0;
+
+ dbg_trace("[%s] %p\n", __func__, buf);
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ if (driver == NULL)
+ return scnprintf(buf, PAGE_SIZE,
+ "There is no gadget attached!\n");
+
+ n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n",
+ (driver->function ? driver->function : ""));
+ n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
+ driver->speed);
+
+ return n;
+}
+static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
+
+/* Maximum event message length */
+#define DBG_DATA_MSG 64UL
+
+/* Maximum event messages */
+#define DBG_DATA_MAX 128UL
+
+/* Event buffer descriptor */
+static struct {
+ char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */
+ unsigned idx; /* index */
+ unsigned tty; /* print to console? */
+ rwlock_t lck; /* lock */
+} dbg_data = {
+ .idx = 0,
+ .tty = 0,
+ .lck = __RW_LOCK_UNLOCKED(lck)
+};
+
+/**
+ * dbg_dec: decrements debug event index
+ * @idx: buffer index
+ */
+static void dbg_dec(unsigned *idx)
+{
+ *idx = (*idx - 1) & (DBG_DATA_MAX-1);
+}
+
+/**
+ * dbg_inc: increments debug event index
+ * @idx: buffer index
+ */
+static void dbg_inc(unsigned *idx)
+{
+ *idx = (*idx + 1) & (DBG_DATA_MAX-1);
+}
+
+/**
+ * dbg_print: prints the common part of the event
+ * @addr: endpoint address
+ * @name: event name
+ * @status: status
+ * @extra: extra information
+ */
+static void dbg_print(u8 addr, const char *name, int status, const char *extra)
+{
+ struct timeval tval;
+ unsigned int stamp;
+ unsigned long flags;
+
+ write_lock_irqsave(&dbg_data.lck, flags);
+
+ do_gettimeofday(&tval);
+ stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */
+ stamp = stamp * 1000000 + tval.tv_usec;
+
+ scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
+ "%04X\t» %02X %-7.7s %4i «\t%s\n",
+ stamp, addr, name, status, extra);
+
+ dbg_inc(&dbg_data.idx);
+
+ write_unlock_irqrestore(&dbg_data.lck, flags);
+
+ if (dbg_data.tty != 0)
+ pr_notice("%04X\t» %02X %-7.7s %4i «\t%s\n",
+ stamp, addr, name, status, extra);
+}
+
+/**
+ * dbg_done: prints a DONE event
+ * @addr: endpoint address
+ * @td: transfer descriptor
+ * @status: status
+ */
+static void dbg_done(u8 addr, const u32 token, int status)
+{
+ char msg[DBG_DATA_MSG];
+
+ scnprintf(msg, sizeof(msg), "%d %02X",
+ (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
+ (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS));
+ dbg_print(addr, "DONE", status, msg);
+}
+
+/**
+ * dbg_event: prints a generic event
+ * @addr: endpoint address
+ * @name: event name
+ * @status: status
+ */
+static void dbg_event(u8 addr, const char *name, int status)
+{
+ if (name != NULL)
+ dbg_print(addr, name, status, "");
+}
+
+/*
+ * dbg_queue: prints a QUEUE event
+ * @addr: endpoint address
+ * @req: USB request
+ * @status: status
+ */
+static void dbg_queue(u8 addr, const struct usb_request *req, int status)
+{
+ char msg[DBG_DATA_MSG];
+
+ if (req != NULL) {
+ scnprintf(msg, sizeof(msg),
+ "%d %d", !req->no_interrupt, req->length);
+ dbg_print(addr, "QUEUE", status, msg);
+ }
+}
+
+/**
+ * dbg_setup: prints a SETUP event
+ * @addr: endpoint address
+ * @req: setup request
+ */
+static void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
+{
+ char msg[DBG_DATA_MSG];
+
+ if (req != NULL) {
+ scnprintf(msg, sizeof(msg),
+ "%02X %02X %04X %04X %d", req->bRequestType,
+ req->bRequest, le16_to_cpu(req->wValue),
+ le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
+ dbg_print(addr, "SETUP", 0, msg);
+ }
+}
+
+/**
+ * show_events: displays the event buffer
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_events(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ unsigned i, j, n = 0;
+
+ dbg_trace("[%s] %p\n", __func__, buf);
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ read_lock_irqsave(&dbg_data.lck, flags);
+
+ i = dbg_data.idx;
+ for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
+ n += strlen(dbg_data.buf[i]);
+ if (n >= PAGE_SIZE) {
+ n -= strlen(dbg_data.buf[i]);
+ break;
+ }
+ }
+ for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
+ j += scnprintf(buf + j, PAGE_SIZE - j,
+ "%s", dbg_data.buf[i]);
+
+ read_unlock_irqrestore(&dbg_data.lck, flags);
+
+ return n;
+}
+
+/**
+ * store_events: configure if events are going to be also printed to console
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_events(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned tty;
+
+ dbg_trace("[%s] %p, %d\n", __func__, buf, count);
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ goto done;
+ }
+
+ if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
+ dev_err(dev, "<1|0>: enable|disable console log\n");
+ goto done;
+ }
+
+ dbg_data.tty = tty;
+ dev_info(dev, "tty = %u", dbg_data.tty);
+
+ done:
+ return count;
+}
+static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
+
+/**
+ * show_inters: interrupt status, enable status and historic
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ u32 intr;
+ unsigned i, j, n = 0;
+
+ dbg_trace("[%s] %p\n", __func__, buf);
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(udc->lock, flags);
+
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "status = %08x\n", hw_read_intr_status());
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "enable = %08x\n", hw_read_intr_enable());
+
+ n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
+ isr_statistics.test);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "» ui = %d\n",
+ isr_statistics.ui);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "» uei = %d\n",
+ isr_statistics.uei);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "» pci = %d\n",
+ isr_statistics.pci);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "» uri = %d\n",
+ isr_statistics.uri);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "» sli = %d\n",
+ isr_statistics.sli);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
+ isr_statistics.none);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
+ isr_statistics.hndl.cnt);
+
+ for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
+ i &= ISR_MASK;
+ intr = isr_statistics.hndl.buf[i];
+
+ if (USBi_UI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "ui ");
+ intr &= ~USBi_UI;
+ if (USBi_UEI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
+ intr &= ~USBi_UEI;
+ if (USBi_PCI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
+ intr &= ~USBi_PCI;
+ if (USBi_URI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
+ intr &= ~USBi_URI;
+ if (USBi_SLI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
+ intr &= ~USBi_SLI;
+ if (intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
+ if (isr_statistics.hndl.buf[i])
+ n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
+ }
+
+ spin_unlock_irqrestore(udc->lock, flags);
+
+ return n;
+}
+
+/**
+ * store_inters: enable & force or disable an individual interrutps
+ * (to be used for test purposes only)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ unsigned en, bit;
+
+ dbg_trace("[%s] %p, %d\n", __func__, buf, count);
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ goto done;
+ }
+
+ if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
+ dev_err(dev, "<1|0> <bit>: enable|disable interrupt");
+ goto done;
+ }
+
+ spin_lock_irqsave(udc->lock, flags);
+ if (en) {
+ if (hw_intr_force(bit))
+ dev_err(dev, "invalid bit number\n");
+ else
+ isr_statistics.test++;
+ } else {
+ if (hw_intr_clear(bit))
+ dev_err(dev, "invalid bit number\n");
+ }
+ spin_unlock_irqrestore(udc->lock, flags);
+
+ done:
+ return count;
+}
+static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
+
+/**
+ * show_port_test: reads port test mode
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_port_test(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ unsigned mode;
+
+ dbg_trace("[%s] %p\n", __func__, buf);
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(udc->lock, flags);
+ mode = hw_port_test_get();
+ spin_unlock_irqrestore(udc->lock, flags);
+
+ return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
+}
+
+/**
+ * store_port_test: writes port test mode
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_port_test(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ unsigned mode;
+
+ dbg_trace("[%s] %p, %d\n", __func__, buf, count);
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ goto done;
+ }
+
+ if (sscanf(buf, "%u", &mode) != 1) {
+ dev_err(dev, "<mode>: set port test mode");
+ goto done;
+ }
+
+ spin_lock_irqsave(udc->lock, flags);
+ if (hw_port_test_set(mode))
+ dev_err(dev, "invalid mode\n");
+ spin_unlock_irqrestore(udc->lock, flags);
+
+ done:
+ return count;
+}
+static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
+ show_port_test, store_port_test);
+
+/**
+ * show_qheads: DMA contents of all queue heads
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ unsigned i, j, n = 0;
+
+ dbg_trace("[%s] %p\n", __func__, buf);
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(udc->lock, flags);
+ for (i = 0; i < hw_ep_max; i++) {
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "EP=%02i: RX=%08X TX=%08X\n",
+ i, (u32)mEp->qh[RX].dma, (u32)mEp->qh[TX].dma);
+ for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ " %04X: %08X %08X\n", j,
+ *((u32 *)mEp->qh[RX].ptr + j),
+ *((u32 *)mEp->qh[TX].ptr + j));
+ }
+ }
+ spin_unlock_irqrestore(udc->lock, flags);
+
+ return n;
+}
+static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
+
+/**
+ * show_registers: dumps all registers
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_registers(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ u32 dump[512];
+ unsigned i, k, n = 0;
+
+ dbg_trace("[%s] %p\n", __func__, buf);
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(udc->lock, flags);
+ k = hw_register_read(dump, sizeof(dump)/sizeof(u32));
+ spin_unlock_irqrestore(udc->lock, flags);
+
+ for (i = 0; i < k; i++) {
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "reg[0x%04X] = 0x%08X\n",
+ i * (unsigned)sizeof(u32), dump[i]);
+ }
+
+ return n;
+}
+
+/**
+ * store_registers: writes value to register address
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_registers(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long addr, data, flags;
+
+ dbg_trace("[%s] %p, %d\n", __func__, buf, count);
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ goto done;
+ }
+
+ if (sscanf(buf, "%li %li", &addr, &data) != 2) {
+ dev_err(dev, "<addr> <data>: write data to register address");
+ goto done;
+ }
+
+ spin_lock_irqsave(udc->lock, flags);
+ if (hw_register_write(addr, data))
+ dev_err(dev, "invalid address range\n");
+ spin_unlock_irqrestore(udc->lock, flags);
+
+ done:
+ return count;
+}
+static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
+ show_registers, store_registers);
+
+/**
+ * show_requests: DMA contents of all requests currently queued (all endpts)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ struct list_head *ptr = NULL;
+ struct ci13xxx_req *req = NULL;
+ unsigned i, j, k, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
+
+ dbg_trace("[%s] %p\n", __func__, buf);
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(udc->lock, flags);
+ for (i = 0; i < hw_ep_max; i++)
+ for (k = RX; k <= TX; k++)
+ list_for_each(ptr, &udc->ci13xxx_ep[i].qh[k].queue)
+ {
+ req = list_entry(ptr,
+ struct ci13xxx_req, queue);
+
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "EP=%02i: TD=%08X %s\n",
+ i, (u32)req->dma,
+ ((k == RX) ? "RX" : "TX"));
+
+ for (j = 0; j < qSize; j++)
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ " %04X: %08X\n", j,
+ *((u32 *)req->ptr + j));
+ }
+ spin_unlock_irqrestore(udc->lock, flags);
+
+ return n;
+}
+static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
+
+/**
+ * dbg_create_files: initializes the attribute interface
+ * @dev: device
+ *
+ * This function returns an error code
+ */
+__maybe_unused static int dbg_create_files(struct device *dev)
+{
+ int retval = 0;
+
+ if (dev == NULL)
+ return -EINVAL;
+ retval = device_create_file(dev, &dev_attr_device);
+ if (retval)
+ goto done;
+ retval = device_create_file(dev, &dev_attr_driver);
+ if (retval)
+ goto rm_device;
+ retval = device_create_file(dev, &dev_attr_events);
+ if (retval)
+ goto rm_driver;
+ retval = device_create_file(dev, &dev_attr_inters);
+ if (retval)
+ goto rm_events;
+ retval = device_create_file(dev, &dev_attr_port_test);
+ if (retval)
+ goto rm_inters;
+ retval = device_create_file(dev, &dev_attr_qheads);
+ if (retval)
+ goto rm_port_test;
+ retval = device_create_file(dev, &dev_attr_registers);
+ if (retval)
+ goto rm_qheads;
+ retval = device_create_file(dev, &dev_attr_requests);
+ if (retval)
+ goto rm_registers;
+ return 0;
+
+ rm_registers:
+ device_remove_file(dev, &dev_attr_registers);
+ rm_qheads:
+ device_remove_file(dev, &dev_attr_qheads);
+ rm_port_test:
+ device_remove_file(dev, &dev_attr_port_test);
+ rm_inters:
+ device_remove_file(dev, &dev_attr_inters);
+ rm_events:
+ device_remove_file(dev, &dev_attr_events);
+ rm_driver:
+ device_remove_file(dev, &dev_attr_driver);
+ rm_device:
+ device_remove_file(dev, &dev_attr_device);
+ done:
+ return retval;
+}
+
+/**
+ * dbg_remove_files: destroys the attribute interface
+ * @dev: device
+ *
+ * This function returns an error code
+ */
+__maybe_unused static int dbg_remove_files(struct device *dev)
+{
+ if (dev == NULL)
+ return -EINVAL;
+ device_remove_file(dev, &dev_attr_requests);
+ device_remove_file(dev, &dev_attr_registers);
+ device_remove_file(dev, &dev_attr_qheads);
+ device_remove_file(dev, &dev_attr_port_test);
+ device_remove_file(dev, &dev_attr_inters);
+ device_remove_file(dev, &dev_attr_events);
+ device_remove_file(dev, &dev_attr_driver);
+ device_remove_file(dev, &dev_attr_device);
+ return 0;
+}
+
+/******************************************************************************
+ * UTIL block
+ *****************************************************************************/
+/**
+ * _usb_addr: calculates endpoint address from direction & number
+ * @ep: endpoint
+ */
+static inline u8 _usb_addr(struct ci13xxx_ep *ep)
+{
+ return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
+}
+
+/**
+ * _hardware_queue: configures a request at hardware level
+ * @gadget: gadget
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ */
+static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+ unsigned i;
+
+ trace("%p, %p", mEp, mReq);
+
+ /* don't queue twice */
+ if (mReq->req.status == -EALREADY)
+ return -EALREADY;
+
+ if (hw_ep_is_primed(mEp->num, mEp->dir))
+ return -EBUSY;
+
+ mReq->req.status = -EALREADY;
+
+ if (mReq->req.length && !mReq->req.dma) {
+ mReq->req.dma = \
+ dma_map_single(mEp->device, mReq->req.buf,
+ mReq->req.length, mEp->dir ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ if (mReq->req.dma == 0)
+ return -ENOMEM;
+
+ mReq->map = 1;
+ }
+
+ /*
+ * TD configuration
+ * TODO - handle requests which spawns into several TDs
+ */
+ memset(mReq->ptr, 0, sizeof(*mReq->ptr));
+ mReq->ptr->next |= TD_TERMINATE;
+ mReq->ptr->token = mReq->req.length << ffs_nr(TD_TOTAL_BYTES);
+ mReq->ptr->token &= TD_TOTAL_BYTES;
+ mReq->ptr->token |= TD_IOC;
+ mReq->ptr->token |= TD_STATUS_ACTIVE;
+ mReq->ptr->page[0] = mReq->req.dma;
+ for (i = 1; i < 5; i++)
+ mReq->ptr->page[i] =
+ (mReq->req.dma + i * PAGE_SIZE) & ~TD_RESERVED_MASK;
+
+ /*
+ * QH configuration
+ * At this point it's guaranteed exclusive access to qhead
+ * (endpt is not primed) so it's no need to use tripwire
+ */
+ mEp->qh[mEp->dir].ptr->td.next = mReq->dma; /* TERMINATE = 0 */
+ mEp->qh[mEp->dir].ptr->td.token &= ~TD_STATUS; /* clear status */
+ if (mReq->req.zero == 0)
+ mEp->qh[mEp->dir].ptr->cap |= QH_ZLT;
+ else
+ mEp->qh[mEp->dir].ptr->cap &= ~QH_ZLT;
+
+ wmb(); /* synchronize before ep prime */
+
+ return hw_ep_prime(mEp->num, mEp->dir,
+ mEp->type == USB_ENDPOINT_XFER_CONTROL);
+}
+
+/**
+ * _hardware_dequeue: handles a request at hardware level
+ * @gadget: gadget
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ */
+static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+ trace("%p, %p", mEp, mReq);
+
+ if (mReq->req.status != -EALREADY)
+ return -EINVAL;
+
+ if (hw_ep_is_primed(mEp->num, mEp->dir))
+ hw_ep_flush(mEp->num, mEp->dir);
+
+ mReq->req.status = 0;
+
+ if (mReq->map) {
+ dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
+ mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ mReq->req.dma = 0;
+ mReq->map = 0;
+ }
+
+ mReq->req.status = mReq->ptr->token & TD_STATUS;
+ if ((TD_STATUS_ACTIVE & mReq->req.status) != 0)
+ mReq->req.status = -ECONNRESET;
+ else if ((TD_STATUS_HALTED & mReq->req.status) != 0)
+ mReq->req.status = -1;
+ else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
+ mReq->req.status = -1;
+ else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
+ mReq->req.status = -1;
+
+ mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES;
+ mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
+ mReq->req.actual = mReq->req.length - mReq->req.actual;
+ mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual;
+
+ return mReq->req.actual;
+}
+
+/**
+ * _ep_nuke: dequeues all endpoint requests
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ * Caller must hold lock
+ */
+static int _ep_nuke(struct ci13xxx_ep *mEp)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+ trace("%p", mEp);
+
+ if (mEp == NULL)
+ return -EINVAL;
+
+ hw_ep_flush(mEp->num, mEp->dir);
+
+ while (!list_empty(&mEp->qh[mEp->dir].queue)) {
+
+ /* pop oldest request */
+ struct ci13xxx_req *mReq = \
+ list_entry(mEp->qh[mEp->dir].queue.next,
+ struct ci13xxx_req, queue);
+ list_del_init(&mReq->queue);
+ mReq->req.status = -ESHUTDOWN;
+
+ if (!mReq->req.no_interrupt && mReq->req.complete != NULL) {
+ spin_unlock(mEp->lock);
+ mReq->req.complete(&mEp->ep, &mReq->req);
+ spin_lock(mEp->lock);
+ }
+ }
+ return 0;
+}
+
+/**
+ * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
+ * @gadget: gadget
+ *
+ * This function returns an error code
+ * Caller must hold lock
+ */
+static int _gadget_stop_activity(struct usb_gadget *gadget)
+__releases(udc->lock)
+__acquires(udc->lock)
+{
+ struct usb_ep *ep;
+ struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
+ struct ci13xxx_ep *mEp = container_of(gadget->ep0,
+ struct ci13xxx_ep, ep);
+
+ trace("%p", gadget);
+
+ if (gadget == NULL)
+ return -EINVAL;
+
+ spin_unlock(udc->lock);
+
+ /* flush all endpoints */
+ gadget_for_each_ep(ep, gadget) {
+ usb_ep_fifo_flush(ep);
+ }
+ usb_ep_fifo_flush(gadget->ep0);
+
+ udc->driver->disconnect(gadget);
+
+ /* make sure to disable all endpoints */
+ gadget_for_each_ep(ep, gadget) {
+ usb_ep_disable(ep);
+ }
+ usb_ep_disable(gadget->ep0);
+
+ if (mEp->status != NULL) {
+ usb_ep_free_request(gadget->ep0, mEp->status);
+ mEp->status = NULL;
+ }
+
+ spin_lock(udc->lock);
+
+ return 0;
+}
+
+/******************************************************************************
+ * ISR block
+ *****************************************************************************/
+/**
+ * isr_reset_handler: USB reset interrupt handler
+ * @udc: UDC device
+ *
+ * This function resets USB engine after a bus reset occurred
+ */
+static void isr_reset_handler(struct ci13xxx *udc)
+__releases(udc->lock)
+__acquires(udc->lock)
+{
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[0];
+ int retval;
+
+ trace("%p", udc);
+
+ if (udc == NULL) {
+ err("EINVAL");
+ return;
+ }
+
+ dbg_event(0xFF, "BUS RST", 0);
+
+ retval = _gadget_stop_activity(&udc->gadget);
+ if (retval)
+ goto done;
+
+ retval = hw_usb_reset();
+ if (retval)
+ goto done;
+
+ spin_unlock(udc->lock);
+ retval = usb_ep_enable(&mEp->ep, &ctrl_endpt_desc);
+ if (!retval) {
+ mEp->status = usb_ep_alloc_request(&mEp->ep, GFP_KERNEL);
+ if (mEp->status == NULL) {
+ usb_ep_disable(&mEp->ep);
+ retval = -ENOMEM;
+ }
+ }
+ spin_lock(udc->lock);
+
+ done:
+ if (retval)
+ err("error: %i", retval);
+}
+
+/**
+ * isr_get_status_complete: get_status request complete function
+ * @ep: endpoint
+ * @req: request handled
+ *
+ * Caller must release lock
+ */
+static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ trace("%p, %p", ep, req);
+
+ if (ep == NULL || req == NULL) {
+ err("EINVAL");
+ return;
+ }
+
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+}
+
+/**
+ * isr_get_status_response: get_status request response
+ * @ep: endpoint
+ * @setup: setup request packet
+ *
+ * This function returns an error code
+ */
+static int isr_get_status_response(struct ci13xxx_ep *mEp,
+ struct usb_ctrlrequest *setup)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+ struct usb_request *req = NULL;
+ gfp_t gfp_flags = GFP_ATOMIC;
+ int dir, num, retval;
+
+ trace("%p, %p", mEp, setup);
+
+ if (mEp == NULL || setup == NULL)
+ return -EINVAL;
+
+ spin_unlock(mEp->lock);
+ req = usb_ep_alloc_request(&mEp->ep, gfp_flags);
+ spin_lock(mEp->lock);
+ if (req == NULL)
+ return -ENOMEM;
+
+ req->complete = isr_get_status_complete;
+ req->length = 2;
+ req->buf = kzalloc(req->length, gfp_flags);
+ if (req->buf == NULL) {
+ retval = -ENOMEM;
+ goto err_free_req;
+ }
+
+ if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+ /* TODO: D1 - Remote Wakeup; D0 - Self Powered */
+ retval = 0;
+ } else if ((setup->bRequestType & USB_RECIP_MASK) \
+ == USB_RECIP_ENDPOINT) {
+ dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
+ TX : RX;
+ num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK;
+ *((u16 *)req->buf) = hw_ep_get_halt(num, dir);
+ }
+ /* else do nothing; reserved for future use */
+
+ spin_unlock(mEp->lock);
+ retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
+ spin_lock(mEp->lock);
+ if (retval)
+ goto err_free_buf;
+
+ return 0;
+
+ err_free_buf:
+ kfree(req->buf);
+ err_free_req:
+ spin_unlock(mEp->lock);
+ usb_ep_free_request(&mEp->ep, req);
+ spin_lock(mEp->lock);
+ return retval;
+}
+
+/**
+ * isr_setup_status_phase: queues the status phase of a setup transation
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ */
+static int isr_setup_status_phase(struct ci13xxx_ep *mEp)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+ int retval;
+
+ trace("%p", mEp);
+
+ /* mEp is always valid & configured */
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+ mEp->status->no_interrupt = 1;
+
+ spin_unlock(mEp->lock);
+ retval = usb_ep_queue(&mEp->ep, mEp->status, GFP_ATOMIC);
+ spin_lock(mEp->lock);
+
+ return retval;
+}
+
+/**
+ * isr_tr_complete_low: transaction complete low level handler
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ * Caller must hold lock
+ */
+static int isr_tr_complete_low(struct ci13xxx_ep *mEp)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+ struct ci13xxx_req *mReq;
+ int retval;
+
+ trace("%p", mEp);
+
+ if (list_empty(&mEp->qh[mEp->dir].queue))
+ return -EINVAL;
+
+ /* pop oldest request */
+ mReq = list_entry(mEp->qh[mEp->dir].queue.next,
+ struct ci13xxx_req, queue);
+ list_del_init(&mReq->queue);
+
+ retval = _hardware_dequeue(mEp, mReq);
+ if (retval < 0) {
+ dbg_event(_usb_addr(mEp), "DONE", retval);
+ goto done;
+ }
+
+ dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
+
+ if (!mReq->req.no_interrupt && mReq->req.complete != NULL) {
+ spin_unlock(mEp->lock);
+ mReq->req.complete(&mEp->ep, &mReq->req);
+ spin_lock(mEp->lock);
+ }
+
+ if (!list_empty(&mEp->qh[mEp->dir].queue)) {
+ mReq = list_entry(mEp->qh[mEp->dir].queue.next,
+ struct ci13xxx_req, queue);
+ _hardware_enqueue(mEp, mReq);
+ }
+
+ done:
+ return retval;
+}
+
+/**
+ * isr_tr_complete_handler: transaction complete interrupt handler
+ * @udc: UDC descriptor
+ *
+ * This function handles traffic events
+ */
+static void isr_tr_complete_handler(struct ci13xxx *udc)
+__releases(udc->lock)
+__acquires(udc->lock)
+{
+ unsigned i;
+
+ trace("%p", udc);
+
+ if (udc == NULL) {
+ err("EINVAL");
+ return;
+ }
+
+ for (i = 0; i < hw_ep_max; i++) {
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+ int type, num, err = -EINVAL;
+ struct usb_ctrlrequest req;
+
+
+ if (mEp->desc == NULL)
+ continue; /* not configured */
+
+ if ((mEp->dir == RX && hw_test_and_clear_complete(i)) ||
+ (mEp->dir == TX && hw_test_and_clear_complete(i + 16))) {
+ err = isr_tr_complete_low(mEp);
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (err > 0) /* needs status phase */
+ err = isr_setup_status_phase(mEp);
+ if (err < 0) {
+ dbg_event(_usb_addr(mEp),
+ "ERROR", err);
+ spin_unlock(udc->lock);
+ if (usb_ep_set_halt(&mEp->ep))
+ err("error: ep_set_halt");
+ spin_lock(udc->lock);
+ }
+ }
+ }
+
+ if (mEp->type != USB_ENDPOINT_XFER_CONTROL ||
+ !hw_test_and_clear_setup_status(i))
+ continue;
+
+ if (i != 0) {
+ warn("ctrl traffic received at endpoint");
+ continue;
+ }
+
+ /* read_setup_packet */
+ do {
+ hw_test_and_set_setup_guard();
+ memcpy(&req, &mEp->qh[RX].ptr->setup, sizeof(req));
+ } while (!hw_test_and_clear_setup_guard());
+
+ type = req.bRequestType;
+
+ mEp->dir = (type & USB_DIR_IN) ? TX : RX;
+
+ dbg_setup(_usb_addr(mEp), &req);
+
+ switch (req.bRequest) {
+ case USB_REQ_CLEAR_FEATURE:
+ if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+ le16_to_cpu(req.wValue) != USB_ENDPOINT_HALT)
+ goto delegate;
+ if (req.wLength != 0)
+ break;
+ num = le16_to_cpu(req.wIndex);
+ num &= USB_ENDPOINT_NUMBER_MASK;
+ if (!udc->ci13xxx_ep[num].wedge) {
+ spin_unlock(udc->lock);
+ err = usb_ep_clear_halt(
+ &udc->ci13xxx_ep[num].ep);
+ spin_lock(udc->lock);
+ if (err)
+ break;
+ }
+ err = isr_setup_status_phase(mEp);
+ break;
+ case USB_REQ_GET_STATUS:
+ if (type != (USB_DIR_IN|USB_RECIP_DEVICE) &&
+ type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
+ type != (USB_DIR_IN|USB_RECIP_INTERFACE))
+ goto delegate;
+ if (le16_to_cpu(req.wLength) != 2 ||
+ le16_to_cpu(req.wValue) != 0)
+ break;
+ err = isr_get_status_response(mEp, &req);
+ break;
+ case USB_REQ_SET_ADDRESS:
+ if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
+ goto delegate;
+ if (le16_to_cpu(req.wLength) != 0 ||
+ le16_to_cpu(req.wIndex) != 0)
+ break;
+ err = hw_usb_set_address((u8)le16_to_cpu(req.wValue));
+ if (err)
+ break;
+ err = isr_setup_status_phase(mEp);
+ break;
+ case USB_REQ_SET_FEATURE:
+ if (type != (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+ le16_to_cpu(req.wValue) != USB_ENDPOINT_HALT)
+ goto delegate;
+ if (req.wLength != 0)
+ break;
+ num = le16_to_cpu(req.wIndex);
+ num &= USB_ENDPOINT_NUMBER_MASK;
+
+ spin_unlock(udc->lock);
+ err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
+ spin_lock(udc->lock);
+ if (err)
+ break;
+ err = isr_setup_status_phase(mEp);
+ break;
+ default:
+delegate:
+ if (req.wLength == 0) /* no data phase */
+ mEp->dir = TX;
+
+ spin_unlock(udc->lock);
+ err = udc->driver->setup(&udc->gadget, &req);
+ spin_lock(udc->lock);
+ break;
+ }
+
+ if (err < 0) {
+ dbg_event(_usb_addr(mEp), "ERROR", err);
+
+ spin_unlock(udc->lock);
+ if (usb_ep_set_halt(&mEp->ep))
+ err("error: ep_set_halt");
+ spin_lock(udc->lock);
+ }
+ }
+}
+
+/******************************************************************************
+ * ENDPT block
+ *****************************************************************************/
+/**
+ * ep_enable: configure endpoint, making it usable
+ *
+ * Check usb_ep_enable() at "usb_gadget.h" for details
+ */
+static int ep_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ int direction, retval = 0;
+ unsigned long flags;
+
+ trace("%p, %p", ep, desc);
+
+ if (ep == NULL || desc == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ /* only internal SW should enable ctrl endpts */
+
+ mEp->desc = desc;
+
+ if (!list_empty(&mEp->qh[mEp->dir].queue))
+ warn("enabling a non-empty endpoint!");
+
+ mEp->dir = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? TX : RX;
+ mEp->num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ mEp->type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+ mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize);
+
+ direction = mEp->dir;
+ do {
+ dbg_event(_usb_addr(mEp), "ENABLE", 0);
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ mEp->qh[mEp->dir].ptr->cap |= QH_IOS;
+ else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
+ mEp->qh[mEp->dir].ptr->cap &= ~QH_MULT;
+ else
+ mEp->qh[mEp->dir].ptr->cap &= ~QH_ZLT;
+
+ mEp->qh[mEp->dir].ptr->cap |=
+ (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
+ mEp->qh[mEp->dir].ptr->td.next |= TD_TERMINATE; /* needed? */
+
+ retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+ } while (mEp->dir != direction);
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return retval;
+}
+
+/**
+ * ep_disable: endpoint is no longer usable
+ *
+ * Check usb_ep_disable() at "usb_gadget.h" for details
+ */
+static int ep_disable(struct usb_ep *ep)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ int direction, retval = 0;
+ unsigned long flags;
+
+ trace("%p", ep);
+
+ if (ep == NULL)
+ return -EINVAL;
+ else if (mEp->desc == NULL)
+ return -EBUSY;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ /* only internal SW should disable ctrl endpts */
+
+ direction = mEp->dir;
+ do {
+ dbg_event(_usb_addr(mEp), "DISABLE", 0);
+
+ retval |= _ep_nuke(mEp);
+ retval |= hw_ep_disable(mEp->num, mEp->dir);
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+ } while (mEp->dir != direction);
+
+ mEp->desc = NULL;
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return retval;
+}
+
+/**
+ * ep_alloc_request: allocate a request object to use with this endpoint
+ *
+ * Check usb_ep_alloc_request() at "usb_gadget.h" for details
+ */
+static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = NULL;
+ unsigned long flags;
+
+ trace("%p, %i", ep, gfp_flags);
+
+ if (ep == NULL) {
+ err("EINVAL");
+ return NULL;
+ }
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
+ if (mReq != NULL) {
+ INIT_LIST_HEAD(&mReq->queue);
+
+ mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
+ &mReq->dma);
+ if (mReq->ptr == NULL) {
+ kfree(mReq);
+ mReq = NULL;
+ }
+ }
+
+ dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+
+ return (mReq == NULL) ? NULL : &mReq->req;
+}
+
+/**
+ * ep_free_request: frees a request object
+ *
+ * Check usb_ep_free_request() at "usb_gadget.h" for details
+ */
+static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ unsigned long flags;
+
+ trace("%p, %p", ep, req);
+
+ if (ep == NULL || req == NULL) {
+ err("EINVAL");
+ return;
+ } else if (!list_empty(&mReq->queue)) {
+ err("EBUSY");
+ return;
+ }
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ if (mReq->ptr)
+ dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
+ kfree(mReq);
+
+ dbg_event(_usb_addr(mEp), "FREE", 0);
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+}
+
+/**
+ * ep_queue: queues (submits) an I/O request to an endpoint
+ *
+ * Check usb_ep_queue()* at usb_gadget.h" for details
+ */
+static int ep_queue(struct usb_ep *ep, struct usb_request *req,
+ gfp_t __maybe_unused gfp_flags)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ int retval = 0;
+ unsigned long flags;
+
+ trace("%p, %p, %X", ep, req, gfp_flags);
+
+ if (ep == NULL || req == NULL || mEp->desc == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL &&
+ !list_empty(&mEp->qh[mEp->dir].queue)) {
+ _ep_nuke(mEp);
+ retval = -EOVERFLOW;
+ warn("endpoint ctrl %X nuked", _usb_addr(mEp));
+ }
+
+ /* first nuke then test link, e.g. previous status has not sent */
+ if (!list_empty(&mReq->queue)) {
+ retval = -EBUSY;
+ err("request already in queue");
+ goto done;
+ }
+
+ if (req->length > (4 * PAGE_SIZE)) {
+ req->length = (4 * PAGE_SIZE);
+ retval = -EMSGSIZE;
+ warn("request length truncated");
+ }
+
+ dbg_queue(_usb_addr(mEp), req, retval);
+
+ /* push request */
+ mReq->req.status = -EINPROGRESS;
+ mReq->req.actual = 0;
+ list_add_tail(&mReq->queue, &mEp->qh[mEp->dir].queue);
+
+ retval = _hardware_enqueue(mEp, mReq);
+ if (retval == -EALREADY || retval == -EBUSY) {
+ dbg_event(_usb_addr(mEp), "QUEUE", retval);
+ retval = 0;
+ }
+
+ done:
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return retval;
+}
+
+/**
+ * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint
+ *
+ * Check usb_ep_dequeue() at "usb_gadget.h" for details
+ */
+static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ unsigned long flags;
+
+ trace("%p, %p", ep, req);
+
+ if (ep == NULL || req == NULL || mEp->desc == NULL ||
+ list_empty(&mReq->queue) || list_empty(&mEp->qh[mEp->dir].queue))
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
+
+ if (mReq->req.status == -EALREADY)
+ _hardware_dequeue(mEp, mReq);
+
+ /* pop request */
+ list_del_init(&mReq->queue);
+ req->status = -ECONNRESET;
+
+ if (!mReq->req.no_interrupt && mReq->req.complete != NULL) {
+ spin_unlock(mEp->lock);
+ mReq->req.complete(&mEp->ep, &mReq->req);
+ spin_lock(mEp->lock);
+ }
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return 0;
+}
+
+/**
+ * ep_set_halt: sets the endpoint halt feature
+ *
+ * Check usb_ep_set_halt() at "usb_gadget.h" for details
+ */
+static int ep_set_halt(struct usb_ep *ep, int value)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ int direction, retval = 0;
+ unsigned long flags;
+
+ trace("%p, %i", ep, value);
+
+ if (ep == NULL || mEp->desc == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+#ifndef STALL_IN
+ /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
+ if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX &&
+ !list_empty(&mEp->qh[mEp->dir].queue)) {
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return -EAGAIN;
+ }
+#endif
+
+ direction = mEp->dir;
+ do {
+ dbg_event(_usb_addr(mEp), "HALT", value);
+ retval |= hw_ep_set_halt(mEp->num, mEp->dir, value);
+
+ if (!value)
+ mEp->wedge = 0;
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+ } while (mEp->dir != direction);
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return retval;
+}
+
+/**
+ * ep_set_wedge: sets the halt feature and ignores clear requests
+ *
+ * Check usb_ep_set_wedge() at "usb_gadget.h" for details
+ */
+static int ep_set_wedge(struct usb_ep *ep)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ unsigned long flags;
+
+ trace("%p", ep);
+
+ if (ep == NULL || mEp->desc == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ dbg_event(_usb_addr(mEp), "WEDGE", 0);
+ mEp->wedge = 1;
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+
+ return usb_ep_set_halt(ep);
+}
+
+/**
+ * ep_fifo_flush: flushes contents of a fifo
+ *
+ * Check usb_ep_fifo_flush() at "usb_gadget.h" for details
+ */
+static void ep_fifo_flush(struct usb_ep *ep)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ unsigned long flags;
+
+ trace("%p", ep);
+
+ if (ep == NULL) {
+ err("%02X: -EINVAL", _usb_addr(mEp));
+ return;
+ }
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ dbg_event(_usb_addr(mEp), "FFLUSH", 0);
+ hw_ep_flush(mEp->num, mEp->dir);
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+}
+
+/**
+ * Endpoint-specific part of the API to the USB controller hardware
+ * Check "usb_gadget.h" for details
+ */
+static const struct usb_ep_ops usb_ep_ops = {
+ .enable = ep_enable,
+ .disable = ep_disable,
+ .alloc_request = ep_alloc_request,
+ .free_request = ep_free_request,
+ .queue = ep_queue,
+ .dequeue = ep_dequeue,
+ .set_halt = ep_set_halt,
+ .set_wedge = ep_set_wedge,
+ .fifo_flush = ep_fifo_flush,
+};
+
+/******************************************************************************
+ * GADGET block
+ *****************************************************************************/
+/**
+ * Device operations part of the API to the USB controller hardware,
+ * which don't involve endpoints (or i/o)
+ * Check "usb_gadget.h" for details
+ */
+static const struct usb_gadget_ops usb_gadget_ops;
+
+/**
+ * usb_gadget_register_driver: register a gadget driver
+ *
+ * Check usb_gadget_register_driver() at "usb_gadget.h" for details
+ * Interrupts are enabled here
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct ci13xxx *udc = _udc;
+ unsigned long i, k, flags;
+ int retval = -ENOMEM;
+
+ trace("%p", driver);
+
+ if (driver == NULL ||
+ driver->bind == NULL ||
+ driver->unbind == NULL ||
+ driver->setup == NULL ||
+ driver->disconnect == NULL ||
+ driver->suspend == NULL ||
+ driver->resume == NULL)
+ return -EINVAL;
+ else if (udc == NULL)
+ return -ENODEV;
+ else if (udc->driver != NULL)
+ return -EBUSY;
+
+ /* alloc resources */
+ udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev,
+ sizeof(struct ci13xxx_qh),
+ 64, PAGE_SIZE);
+ if (udc->qh_pool == NULL)
+ return -ENOMEM;
+
+ udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev,
+ sizeof(struct ci13xxx_td),
+ 64, PAGE_SIZE);
+ if (udc->td_pool == NULL) {
+ dma_pool_destroy(udc->qh_pool);
+ udc->qh_pool = NULL;
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(udc->lock, flags);
+
+ info("hw_ep_max = %d", hw_ep_max);
+
+ udc->driver = driver;
+ udc->gadget.ops = NULL;
+ udc->gadget.dev.driver = NULL;
+
+ retval = 0;
+ for (i = 0; i < hw_ep_max; i++) {
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+
+ scnprintf(mEp->name, sizeof(mEp->name), "ep%i", (int)i);
+
+ mEp->lock = udc->lock;
+ mEp->device = &udc->gadget.dev;
+ mEp->td_pool = udc->td_pool;
+
+ mEp->ep.name = mEp->name;
+ mEp->ep.ops = &usb_ep_ops;
+ mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
+
+ /* this allocation cannot be random */
+ for (k = RX; k <= TX; k++) {
+ INIT_LIST_HEAD(&mEp->qh[k].queue);
+ mEp->qh[k].ptr = dma_pool_alloc(udc->qh_pool,
+ GFP_KERNEL,
+ &mEp->qh[k].dma);
+ if (mEp->qh[k].ptr == NULL)
+ retval = -ENOMEM;
+ else
+ memset(mEp->qh[k].ptr, 0,
+ sizeof(*mEp->qh[k].ptr));
+ }
+ if (i == 0)
+ udc->gadget.ep0 = &mEp->ep;
+ else
+ list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
+ }
+ if (retval)
+ goto done;
+
+ /* bind gadget */
+ driver->driver.bus = NULL;
+ udc->gadget.ops = &usb_gadget_ops;
+ udc->gadget.dev.driver = &driver->driver;
+
+ spin_unlock_irqrestore(udc->lock, flags);
+ retval = driver->bind(&udc->gadget); /* MAY SLEEP */
+ spin_lock_irqsave(udc->lock, flags);
+
+ if (retval) {
+ udc->gadget.ops = NULL;
+ udc->gadget.dev.driver = NULL;
+ goto done;
+ }
+
+ retval = hw_device_state(udc->ci13xxx_ep[0].qh[RX].dma);
+
+ done:
+ spin_unlock_irqrestore(udc->lock, flags);
+ if (retval)
+ usb_gadget_unregister_driver(driver);
+ return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+/**
+ * usb_gadget_unregister_driver: unregister a gadget driver
+ *
+ * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct ci13xxx *udc = _udc;
+ unsigned long i, k, flags;
+
+ trace("%p", driver);
+
+ if (driver == NULL ||
+ driver->bind == NULL ||
+ driver->unbind == NULL ||
+ driver->setup == NULL ||
+ driver->disconnect == NULL ||
+ driver->suspend == NULL ||
+ driver->resume == NULL ||
+ driver != udc->driver)
+ return -EINVAL;
+
+ spin_lock_irqsave(udc->lock, flags);
+
+ hw_device_state(0);
+
+ /* unbind gadget */
+ if (udc->gadget.ops != NULL) {
+ _gadget_stop_activity(&udc->gadget);
+
+ spin_unlock_irqrestore(udc->lock, flags);
+ driver->unbind(&udc->gadget); /* MAY SLEEP */
+ spin_lock_irqsave(udc->lock, flags);
+
+ udc->gadget.ops = NULL;
+ udc->gadget.dev.driver = NULL;
+ }
+
+ /* free resources */
+ for (i = 0; i < hw_ep_max; i++) {
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+
+ if (i == 0)
+ udc->gadget.ep0 = NULL;
+ else if (!list_empty(&mEp->ep.ep_list))
+ list_del_init(&mEp->ep.ep_list);
+
+ for (k = RX; k <= TX; k++)
+ if (mEp->qh[k].ptr != NULL)
+ dma_pool_free(udc->qh_pool,
+ mEp->qh[k].ptr, mEp->qh[k].dma);
+ }
+
+ udc->driver = NULL;
+
+ spin_unlock_irqrestore(udc->lock, flags);
+
+ if (udc->td_pool != NULL) {
+ dma_pool_destroy(udc->td_pool);
+ udc->td_pool = NULL;
+ }
+ if (udc->qh_pool != NULL) {
+ dma_pool_destroy(udc->qh_pool);
+ udc->qh_pool = NULL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/******************************************************************************
+ * BUS block
+ *****************************************************************************/
+/**
+ * udc_irq: global interrupt handler
+ *
+ * This function returns IRQ_HANDLED if the IRQ has been handled
+ * It locks access to registers
+ */
+static irqreturn_t udc_irq(void)
+{
+ struct ci13xxx *udc = _udc;
+ irqreturn_t retval;
+ u32 intr;
+
+ trace();
+
+ if (udc == NULL) {
+ err("ENODEV");
+ return IRQ_HANDLED;
+ }
+
+ spin_lock(udc->lock);
+ intr = hw_test_and_clear_intr_active();
+ if (intr) {
+ isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr;
+ isr_statistics.hndl.idx &= ISR_MASK;
+ isr_statistics.hndl.cnt++;
+
+ /* order defines priority - do NOT change it */
+ if (USBi_URI & intr) {
+ isr_statistics.uri++;
+ isr_reset_handler(udc);
+ }
+ if (USBi_PCI & intr) {
+ isr_statistics.pci++;
+ udc->gadget.speed = hw_port_is_high_speed() ?
+ USB_SPEED_HIGH : USB_SPEED_FULL;
+ }
+ if (USBi_UEI & intr)
+ isr_statistics.uei++;
+ if (USBi_UI & intr) {
+ isr_statistics.ui++;
+ isr_tr_complete_handler(udc);
+ }
+ if (USBi_SLI & intr)
+ isr_statistics.sli++;
+ retval = IRQ_HANDLED;
+ } else {
+ isr_statistics.none++;
+ retval = IRQ_NONE;
+ }
+ spin_unlock(udc->lock);
+
+ return retval;
+}
+
+/**
+ * udc_release: driver release function
+ * @dev: device
+ *
+ * Currently does nothing
+ */
+static void udc_release(struct device *dev)
+{
+ trace("%p", dev);
+
+ if (dev == NULL)
+ err("EINVAL");
+}
+
+/**
+ * udc_probe: parent probe must call this to initialize UDC
+ * @dev: parent device
+ * @regs: registers base address
+ * @name: driver name
+ *
+ * This function returns an error code
+ * No interrupts active, the IRQ has not been requested yet
+ * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask
+ */
+static int udc_probe(struct device *dev, void __iomem *regs, const char *name)
+{
+ struct ci13xxx *udc;
+ int retval = 0;
+
+ trace("%p, %p, %p", dev, regs, name);
+
+ if (dev == NULL || regs == NULL || name == NULL)
+ return -EINVAL;
+
+ udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL);
+ if (udc == NULL)
+ return -ENOMEM;
+
+ udc->lock = &udc_lock;
+
+ retval = hw_device_reset(regs);
+ if (retval)
+ goto done;
+
+ udc->gadget.ops = NULL;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->gadget.is_dualspeed = 1;
+ udc->gadget.is_otg = 0;
+ udc->gadget.name = name;
+
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
+ udc->gadget.ep0 = NULL;
+
+ strcpy(udc->gadget.dev.bus_id, "gadget");
+ udc->gadget.dev.dma_mask = dev->dma_mask;
+ udc->gadget.dev.parent = dev;
+ udc->gadget.dev.release = udc_release;
+
+ retval = device_register(&udc->gadget.dev);
+ if (retval)
+ goto done;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+ retval = dbg_create_files(&udc->gadget.dev);
+#endif
+ if (retval) {
+ device_unregister(&udc->gadget.dev);
+ goto done;
+ }
+
+ _udc = udc;
+ return retval;
+
+ done:
+ err("error = %i", retval);
+ kfree(udc);
+ _udc = NULL;
+ return retval;
+}
+
+/**
+ * udc_remove: parent remove must call this to remove UDC
+ *
+ * No interrupts active, the IRQ has been released
+ */
+static void udc_remove(void)
+{
+ struct ci13xxx *udc = _udc;
+
+ if (udc == NULL) {
+ err("EINVAL");
+ return;
+ }
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+ dbg_remove_files(&udc->gadget.dev);
+#endif
+ device_unregister(&udc->gadget.dev);
+
+ kfree(udc);
+ _udc = NULL;
+}
+
+/******************************************************************************
+ * PCI block
+ *****************************************************************************/
+/**
+ * ci13xxx_pci_irq: interrut handler
+ * @irq: irq number
+ * @pdev: USB Device Controller interrupt source
+ *
+ * This function returns IRQ_HANDLED if the IRQ has been handled
+ * This is an ISR don't trace, use attribute interface instead
+ */
+static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev)
+{
+ if (irq == 0) {
+ dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!");
+ return IRQ_HANDLED;
+ }
+ return udc_irq();
+}
+
+/**
+ * ci13xxx_pci_probe: PCI probe
+ * @pdev: USB device controller being probed
+ * @id: PCI hotplug ID connecting controller to UDC framework
+ *
+ * This function returns an error code
+ * Allocates basic PCI resources for this USB device controller, and then
+ * invokes the udc_probe() method to start the UDC associated with it
+ */
+static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ void __iomem *regs = NULL;
+ int retval = 0;
+
+ if (id == NULL)
+ return -EINVAL;
+
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto done;
+
+ if (!pdev->irq) {
+ dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
+ retval = -ENODEV;
+ goto disable_device;
+ }
+
+ retval = pci_request_regions(pdev, UDC_DRIVER_NAME);
+ if (retval)
+ goto disable_device;
+
+ /* BAR 0 holds all the registers */
+ regs = pci_iomap(pdev, 0, 0);
+ if (!regs) {
+ dev_err(&pdev->dev, "Error mapping memory!");
+ retval = -EFAULT;
+ goto release_regions;
+ }
+ pci_set_drvdata(pdev, (__force void *)regs);
+
+ pci_set_master(pdev);
+ pci_try_set_mwi(pdev);
+
+ retval = udc_probe(&pdev->dev, regs, UDC_DRIVER_NAME);
+ if (retval)
+ goto iounmap;
+
+ /* our device does not have MSI capability */
+
+ retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED,
+ UDC_DRIVER_NAME, pdev);
+ if (retval)
+ goto gadget_remove;
+
+ return 0;
+
+ gadget_remove:
+ udc_remove();
+ iounmap:
+ pci_iounmap(pdev, regs);
+ release_regions:
+ pci_release_regions(pdev);
+ disable_device:
+ pci_disable_device(pdev);
+ done:
+ return retval;
+}
+
+/**
+ * ci13xxx_pci_remove: PCI remove
+ * @pdev: USB Device Controller being removed
+ *
+ * Reverses the effect of ci13xxx_pci_probe(),
+ * first invoking the udc_remove() and then releases
+ * all PCI resources allocated for this USB device controller
+ */
+static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
+{
+ free_irq(pdev->irq, pdev);
+ udc_remove();
+ pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev));
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+/**
+ * PCI device table
+ * PCI device structure
+ *
+ * Check "pci.h" for details
+ */
+static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
+ { PCI_DEVICE(0x153F, 0x1004) },
+ { PCI_DEVICE(0x153F, 0x1006) },
+ { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table);
+
+static struct pci_driver ci13xxx_pci_driver = {
+ .name = UDC_DRIVER_NAME,
+ .id_table = ci13xxx_pci_id_table,
+ .probe = ci13xxx_pci_probe,
+ .remove = __devexit_p(ci13xxx_pci_remove),
+};
+
+/**
+ * ci13xxx_pci_init: module init
+ *
+ * Driver load
+ */
+static int __init ci13xxx_pci_init(void)
+{
+ return pci_register_driver(&ci13xxx_pci_driver);
+}
+module_init(ci13xxx_pci_init);
+
+/**
+ * ci13xxx_pci_exit: module exit
+ *
+ * Driver unload
+ */
+static void __exit ci13xxx_pci_exit(void)
+{
+ pci_unregister_driver(&ci13xxx_pci_driver);
+}
+module_exit(ci13xxx_pci_exit);
+
+MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
+MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("June 2008");
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
new file mode 100644
index 000000000000..4026e9cede34
--- /dev/null
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -0,0 +1,195 @@
+/*
+ * ci13xxx_udc.h - structures, registers, and macros MIPS USB IP core
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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.
+ *
+ * Description: MIPS USB IP core family device controller
+ * Structures, registers and logging macros
+ */
+
+#ifndef _CI13XXX_h_
+#define _CI13XXX_h_
+
+/******************************************************************************
+ * DEFINE
+ *****************************************************************************/
+#define ENDPT_MAX (16)
+#define CTRL_PAYLOAD_MAX (64)
+#define RX (0) /* similar to USB_DIR_OUT but can be used as an index */
+#define TX (1) /* similar to USB_DIR_IN but can be used as an index */
+
+/******************************************************************************
+ * STRUCTURES
+ *****************************************************************************/
+/* DMA layout of transfer descriptors */
+struct ci13xxx_td {
+ /* 0 */
+ u32 next;
+#define TD_TERMINATE BIT(0)
+ /* 1 */
+ u32 token;
+#define TD_STATUS (0x00FFUL << 0)
+#define TD_STATUS_TR_ERR BIT(3)
+#define TD_STATUS_DT_ERR BIT(5)
+#define TD_STATUS_HALTED BIT(6)
+#define TD_STATUS_ACTIVE BIT(7)
+#define TD_MULTO (0x0003UL << 10)
+#define TD_IOC BIT(15)
+#define TD_TOTAL_BYTES (0x7FFFUL << 16)
+ /* 2 */
+ u32 page[5];
+#define TD_CURR_OFFSET (0x0FFFUL << 0)
+#define TD_FRAME_NUM (0x07FFUL << 0)
+#define TD_RESERVED_MASK (0x0FFFUL << 0)
+} __attribute__ ((packed));
+
+/* DMA layout of queue heads */
+struct ci13xxx_qh {
+ /* 0 */
+ u32 cap;
+#define QH_IOS BIT(15)
+#define QH_MAX_PKT (0x07FFUL << 16)
+#define QH_ZLT BIT(29)
+#define QH_MULT (0x0003UL << 30)
+ /* 1 */
+ u32 curr;
+ /* 2 - 8 */
+ struct ci13xxx_td td;
+ /* 9 */
+ u32 RESERVED;
+ struct usb_ctrlrequest setup;
+} __attribute__ ((packed));
+
+/* Extension of usb_request */
+struct ci13xxx_req {
+ struct usb_request req;
+ unsigned map;
+ struct list_head queue;
+ struct ci13xxx_td *ptr;
+ dma_addr_t dma;
+};
+
+/* Extension of usb_ep */
+struct ci13xxx_ep {
+ struct usb_ep ep;
+ const struct usb_endpoint_descriptor *desc;
+ u8 dir;
+ u8 num;
+ u8 type;
+ char name[16];
+ struct {
+ struct list_head queue;
+ struct ci13xxx_qh *ptr;
+ dma_addr_t dma;
+ } qh[2];
+ struct usb_request *status;
+ int wedge;
+
+ /* global resources */
+ spinlock_t *lock;
+ struct device *device;
+ struct dma_pool *td_pool;
+};
+
+/* CI13XXX UDC descriptor & global resources */
+struct ci13xxx {
+ spinlock_t *lock; /* ctrl register bank access */
+
+ struct dma_pool *qh_pool; /* DMA pool for queue heads */
+ struct dma_pool *td_pool; /* DMA pool for transfer descs */
+
+ struct usb_gadget gadget; /* USB slave device */
+ struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
+
+ struct usb_gadget_driver *driver; /* 3rd party gadget driver */
+};
+
+/******************************************************************************
+ * REGISTERS
+ *****************************************************************************/
+/* register size */
+#define REG_BITS (32)
+
+/* HCCPARAMS */
+#define HCCPARAMS_LEN BIT(17)
+
+/* DCCPARAMS */
+#define DCCPARAMS_DEN (0x1F << 0)
+#define DCCPARAMS_DC BIT(7)
+
+/* TESTMODE */
+#define TESTMODE_FORCE BIT(0)
+
+/* USBCMD */
+#define USBCMD_RS BIT(0)
+#define USBCMD_RST BIT(1)
+#define USBCMD_SUTW BIT(13)
+
+/* USBSTS & USBINTR */
+#define USBi_UI BIT(0)
+#define USBi_UEI BIT(1)
+#define USBi_PCI BIT(2)
+#define USBi_URI BIT(6)
+#define USBi_SLI BIT(8)
+
+/* DEVICEADDR */
+#define DEVICEADDR_USBADRA BIT(24)
+#define DEVICEADDR_USBADR (0x7FUL << 25)
+
+/* PORTSC */
+#define PORTSC_SUSP BIT(7)
+#define PORTSC_HSP BIT(9)
+#define PORTSC_PTC (0x0FUL << 16)
+
+/* DEVLC */
+#define DEVLC_PSPD (0x03UL << 25)
+#define DEVLC_PSPD_HS (0x02UL << 25)
+
+/* USBMODE */
+#define USBMODE_CM (0x03UL << 0)
+#define USBMODE_CM_IDLE (0x00UL << 0)
+#define USBMODE_CM_DEVICE (0x02UL << 0)
+#define USBMODE_CM_HOST (0x03UL << 0)
+#define USBMODE_SLOM BIT(3)
+
+/* ENDPTCTRL */
+#define ENDPTCTRL_RXS BIT(0)
+#define ENDPTCTRL_RXT (0x03UL << 2)
+#define ENDPTCTRL_RXR BIT(6) /* reserved for port 0 */
+#define ENDPTCTRL_RXE BIT(7)
+#define ENDPTCTRL_TXS BIT(16)
+#define ENDPTCTRL_TXT (0x03UL << 18)
+#define ENDPTCTRL_TXR BIT(22) /* reserved for port 0 */
+#define ENDPTCTRL_TXE BIT(23)
+
+/******************************************************************************
+ * LOGGING
+ *****************************************************************************/
+#define ci13xxx_printk(level, format, args...) \
+do { \
+ if (_udc == NULL) \
+ printk(level "[%s] " format "\n", __func__, ## args); \
+ else \
+ dev_printk(level, _udc->gadget.dev.parent, \
+ "[%s] " format "\n", __func__, ## args); \
+} while (0)
+
+#define err(format, args...) ci13xxx_printk(KERN_ERR, format, ## args)
+#define warn(format, args...) ci13xxx_printk(KERN_WARNING, format, ## args)
+#define info(format, args...) ci13xxx_printk(KERN_INFO, format, ## args)
+
+#ifdef TRACE
+#define trace(format, args...) ci13xxx_printk(KERN_DEBUG, format, ## args)
+#define dbg_trace(format, args...) dev_dbg(dev, format, ##args)
+#else
+#define trace(format, args...) do {} while (0)
+#define dbg_trace(format, args...) do {} while (0)
+#endif
+
+#endif /* _CI13XXX_h_ */
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 9462e30192d8..a36b1175b18d 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -161,7 +161,7 @@ ep_matches (
/* report address */
desc->bEndpointAddress &= USB_DIR_IN;
if (isdigit (ep->name [2])) {
- u8 num = simple_strtol (&ep->name [2], NULL, 10);
+ u8 num = simple_strtoul (&ep->name [2], NULL, 10);
desc->bEndpointAddress |= num;
#ifdef MANY_ENDPOINTS
} else if (desc->bEndpointAddress & USB_DIR_IN) {
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index d8fc9b32fe36..c0916c7b217e 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -279,6 +279,13 @@ static int pn_net_mtu(struct net_device *dev, int new_mtu)
return err;
}
+static const struct net_device_ops pn_netdev_ops = {
+ .ndo_open = pn_net_open,
+ .ndo_stop = pn_net_close,
+ .ndo_start_xmit = pn_net_xmit,
+ .ndo_change_mtu = pn_net_mtu,
+};
+
static void pn_net_setup(struct net_device *dev)
{
dev->features = 0;
@@ -290,12 +297,9 @@ static void pn_net_setup(struct net_device *dev)
dev->addr_len = 1;
dev->tx_queue_len = 1;
+ dev->netdev_ops = &pn_netdev_ops;
dev->destructor = free_netdev;
dev->header_ops = &phonet_header_ops;
- dev->open = pn_net_open;
- dev->stop = pn_net_close;
- dev->hard_start_xmit = pn_net_xmit; /* mandatory */
- dev->change_mtu = pn_net_mtu;
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 2e71368f45b4..b10fa31cc915 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1,7 +1,7 @@
/*
* file_storage.c -- File-backed USB Storage Gadget, for USB development
*
- * Copyright (C) 2003-2007 Alan Stern
+ * Copyright (C) 2003-2008 Alan Stern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,16 +38,17 @@
/*
* The File-backed Storage Gadget acts as a USB Mass Storage device,
- * appearing to the host as a disk drive. In addition to providing an
- * example of a genuinely useful gadget driver for a USB device, it also
- * illustrates a technique of double-buffering for increased throughput.
- * Last but not least, it gives an easy way to probe the behavior of the
- * Mass Storage drivers in a USB host.
+ * appearing to the host as a disk drive or as a CD-ROM drive. In addition
+ * to providing an example of a genuinely useful gadget driver for a USB
+ * device, it also illustrates a technique of double-buffering for increased
+ * throughput. Last but not least, it gives an easy way to probe the
+ * behavior of the Mass Storage drivers in a USB host.
*
* Backing storage is provided by a regular file or a block device, specified
* by the "file" module parameter. Access can be limited to read-only by
- * setting the optional "ro" module parameter. The gadget will indicate that
- * it has removable media if the optional "removable" module parameter is set.
+ * setting the optional "ro" module parameter. (For CD-ROM emulation,
+ * access is always read-only.) The gadget will indicate that it has
+ * removable media if the optional "removable" module parameter is set.
*
* The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI),
* and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected
@@ -64,7 +65,12 @@
* The default number of LUNs is taken from the number of "file" elements;
* it is 1 if "file" is not given. If "removable" is not set then a backing
* file must be specified for each LUN. If it is set, then an unspecified
- * or empty backing filename means the LUN's medium is not loaded.
+ * or empty backing filename means the LUN's medium is not loaded. Ideally
+ * each LUN would be settable independently as a disk drive or a CD-ROM
+ * drive, but currently all LUNs have to be the same type. The CD-ROM
+ * emulation includes a single data track and no audio tracks; hence there
+ * need be only one backing file per LUN. Note also that the CD-ROM block
+ * length is set to 512 rather than the more common value 2048.
*
* Requirements are modest; only a bulk-in and a bulk-out endpoint are
* needed (an interrupt-out endpoint is also needed for CBI). The memory
@@ -91,6 +97,8 @@
* USB device controller (usually true),
* boolean to permit the driver to halt
* bulk endpoints
+ * cdrom Default false, boolean for whether to emulate
+ * a CD-ROM drive
* transport=XXX Default BBB, transport name (CB, CBI, or BBB)
* protocol=YYY Default SCSI, protocol name (RBC, 8020 or
* ATAPI, QIC, UFI, 8070, or SCSI;
@@ -103,15 +111,16 @@
* PAGE_CACHE_SIZE)
*
* If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro",
- * "removable", "luns", and "stall" options are available; default values
- * are used for everything else.
+ * "removable", "luns", "stall", and "cdrom" options are available; default
+ * values are used for everything else.
*
* The pathnames of the backing files and the ro settings are available in
* the attribute files "file" and "ro" in the lun<n> subdirectory of the
* gadget's sysfs directory. If the "removable" option is set, writing to
* these files will simulate ejecting/loading the medium (writing an empty
* line means eject) and adjusting a write-enable tab. Changes to the ro
- * setting are not allowed when the medium is loaded.
+ * setting are not allowed when the medium is loaded or if CD-ROM emulation
+ * is being used.
*
* This gadget driver is heavily based on "Gadget Zero" by David Brownell.
* The driver's SCSI command interface was based on the "Information
@@ -261,7 +270,7 @@
#define DRIVER_DESC "File-backed Storage Gadget"
#define DRIVER_NAME "g_file_storage"
-#define DRIVER_VERSION "7 August 2007"
+#define DRIVER_VERSION "20 November 2008"
static const char longname[] = DRIVER_DESC;
static const char shortname[] = DRIVER_NAME;
@@ -341,6 +350,7 @@ static struct {
int removable;
int can_stall;
+ int cdrom;
char *transport_parm;
char *protocol_parm;
@@ -359,6 +369,7 @@ static struct {
.protocol_parm = "SCSI",
.removable = 0,
.can_stall = 1,
+ .cdrom = 0,
.vendor = DRIVER_VENDOR_ID,
.product = DRIVER_PRODUCT_ID,
.release = 0xffff, // Use controller chip type
@@ -382,6 +393,9 @@ MODULE_PARM_DESC(removable, "true to simulate removable media");
module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
+module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
+MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
+
/* In the non-TEST version, only the module parameters listed above
* are available. */
@@ -411,6 +425,10 @@ MODULE_PARM_DESC(buflen, "I/O buffer size");
/*-------------------------------------------------------------------------*/
+/* SCSI device types */
+#define TYPE_DISK 0x00
+#define TYPE_CDROM 0x05
+
/* USB protocol value = the transport method */
#define USB_PR_CBI 0x00 // Control/Bulk/Interrupt
#define USB_PR_CB 0x01 // Control/Bulk w/o interrupt
@@ -487,6 +505,8 @@ struct interrupt_data {
#define SC_READ_12 0xa8
#define SC_READ_CAPACITY 0x25
#define SC_READ_FORMAT_CAPACITIES 0x23
+#define SC_READ_HEADER 0x44
+#define SC_READ_TOC 0x43
#define SC_RELEASE 0x17
#define SC_REQUEST_SENSE 0x03
#define SC_RESERVE 0x16
@@ -2006,23 +2026,28 @@ static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
u8 *buf = (u8 *) bh->buf;
static char vendor_id[] = "Linux ";
- static char product_id[] = "File-Stor Gadget";
+ static char product_disk_id[] = "File-Stor Gadget";
+ static char product_cdrom_id[] = "File-CD Gadget ";
if (!fsg->curlun) { // Unsupported LUNs are okay
fsg->bad_lun_okay = 1;
memset(buf, 0, 36);
buf[0] = 0x7f; // Unsupported, no device-type
+ buf[4] = 31; // Additional length
return 36;
}
- memset(buf, 0, 8); // Non-removable, direct-access device
+ memset(buf, 0, 8);
+ buf[0] = (mod_data.cdrom ? TYPE_CDROM : TYPE_DISK);
if (mod_data.removable)
buf[1] = 0x80;
buf[2] = 2; // ANSI SCSI level 2
buf[3] = 2; // SCSI-2 INQUIRY data format
buf[4] = 31; // Additional length
// No special options
- sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, product_id,
+ sprintf(buf + 8, "%-8s%-16s%04x", vendor_id,
+ (mod_data.cdrom ? product_cdrom_id :
+ product_disk_id),
mod_data.release);
return 36;
}
@@ -2101,6 +2126,75 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
}
+static void store_cdrom_address(u8 *dest, int msf, u32 addr)
+{
+ if (msf) {
+ /* Convert to Minutes-Seconds-Frames */
+ addr >>= 2; /* Convert to 2048-byte frames */
+ addr += 2*75; /* Lead-in occupies 2 seconds */
+ dest[3] = addr % 75; /* Frames */
+ addr /= 75;
+ dest[2] = addr % 60; /* Seconds */
+ addr /= 60;
+ dest[1] = addr; /* Minutes */
+ dest[0] = 0; /* Reserved */
+ } else {
+ /* Absolute sector */
+ put_be32(dest, addr);
+ }
+}
+
+static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+{
+ struct lun *curlun = fsg->curlun;
+ int msf = fsg->cmnd[1] & 0x02;
+ u32 lba = get_be32(&fsg->cmnd[2]);
+ u8 *buf = (u8 *) bh->buf;
+
+ if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+ if (lba >= curlun->num_sectors) {
+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
+ return -EINVAL;
+ }
+
+ memset(buf, 0, 8);
+ buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */
+ store_cdrom_address(&buf[4], msf, lba);
+ return 8;
+}
+
+
+static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
+{
+ struct lun *curlun = fsg->curlun;
+ int msf = fsg->cmnd[1] & 0x02;
+ int start_track = fsg->cmnd[6];
+ u8 *buf = (u8 *) bh->buf;
+
+ if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
+ start_track > 1) {
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+
+ memset(buf, 0, 20);
+ buf[1] = (20-2); /* TOC data length */
+ buf[2] = 1; /* First track number */
+ buf[3] = 1; /* Last track number */
+ buf[5] = 0x16; /* Data track, copying allowed */
+ buf[6] = 0x01; /* Only track is number 1 */
+ store_cdrom_address(&buf[8], msf, 0);
+
+ buf[13] = 0x16; /* Lead-out track is data */
+ buf[14] = 0xAA; /* Lead-out track number */
+ store_cdrom_address(&buf[16], msf, curlun->num_sectors);
+ return 20;
+}
+
+
static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
struct lun *curlun = fsg->curlun;
@@ -2848,6 +2942,26 @@ static int do_scsi_command(struct fsg_dev *fsg)
reply = do_read_capacity(fsg, bh);
break;
+ case SC_READ_HEADER:
+ if (!mod_data.cdrom)
+ goto unknown_cmnd;
+ fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+ (3<<7) | (0x1f<<1), 1,
+ "READ HEADER")) == 0)
+ reply = do_read_header(fsg, bh);
+ break;
+
+ case SC_READ_TOC:
+ if (!mod_data.cdrom)
+ goto unknown_cmnd;
+ fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+ (7<<6) | (1<<1), 1,
+ "READ TOC")) == 0)
+ reply = do_read_toc(fsg, bh);
+ break;
+
case SC_READ_FORMAT_CAPACITIES:
fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
@@ -2933,6 +3047,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
// Fall through
default:
+ unknown_cmnd:
fsg->data_size_from_cmnd = 0;
sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]);
if ((reply = check_command(fsg, fsg->cmnd_size,
@@ -3498,6 +3613,7 @@ static int open_backing_file(struct lun *curlun, const char *filename)
struct inode *inode = NULL;
loff_t size;
loff_t num_sectors;
+ loff_t min_sectors;
/* R/W if we can, R/O if we must */
ro = curlun->ro;
@@ -3541,8 +3657,19 @@ static int open_backing_file(struct lun *curlun, const char *filename)
rc = (int) size;
goto out;
}
- num_sectors = size >> 9; // File size in 512-byte sectors
- if (num_sectors == 0) {
+ num_sectors = size >> 9; // File size in 512-byte blocks
+ min_sectors = 1;
+ if (mod_data.cdrom) {
+ num_sectors &= ~3; // Reduce to a multiple of 2048
+ min_sectors = 300*4; // Smallest track is 300 frames
+ if (num_sectors >= 256*60*75*4) {
+ num_sectors = (256*60*75 - 1) * 4;
+ LINFO(curlun, "file too big: %s\n", filename);
+ LINFO(curlun, "using only first %d blocks\n",
+ (int) num_sectors);
+ }
+ }
+ if (num_sectors < min_sectors) {
LINFO(curlun, "file too small: %s\n", filename);
rc = -ETOOSMALL;
goto out;
@@ -3845,9 +3972,12 @@ static int __init fsg_bind(struct usb_gadget *gadget)
goto out;
if (mod_data.removable) { // Enable the store_xxx attributes
- dev_attr_ro.attr.mode = dev_attr_file.attr.mode = 0644;
- dev_attr_ro.store = store_ro;
+ dev_attr_file.attr.mode = 0644;
dev_attr_file.store = store_file;
+ if (!mod_data.cdrom) {
+ dev_attr_ro.attr.mode = 0644;
+ dev_attr_ro.store = store_ro;
+ }
}
/* Find out how many LUNs there should be */
@@ -3872,6 +4002,8 @@ static int __init fsg_bind(struct usb_gadget *gadget)
for (i = 0; i < fsg->nluns; ++i) {
curlun = &fsg->luns[i];
curlun->ro = mod_data.ro[i];
+ if (mod_data.cdrom)
+ curlun->ro = 1;
curlun->dev.release = lun_release;
curlun->dev.parent = &gadget->dev;
curlun->dev.driver = &fsg_driver.driver;
@@ -4031,9 +4163,9 @@ static int __init fsg_bind(struct usb_gadget *gadget)
mod_data.protocol_name, mod_data.protocol_type);
DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n",
mod_data.vendor, mod_data.product, mod_data.release);
- DBG(fsg, "removable=%d, stall=%d, buflen=%u\n",
+ DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n",
mod_data.removable, mod_data.can_stall,
- mod_data.buflen);
+ mod_data.cdrom, mod_data.buflen);
DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task));
set_bit(REGISTERED, &fsg->atomic_bitflags);
@@ -4050,6 +4182,7 @@ out:
fsg->state = FSG_STATE_TERMINATED; // The thread is dead
fsg_unbind(gadget);
close_all_backing_files(fsg);
+ complete(&fsg->thread_notifier);
return rc;
}
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index f40272565098..d6c5bcd40064 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -26,6 +26,7 @@
#include <linux/ioport.h>
#include <linux/types.h>
#include <linux/errno.h>
+#include <linux/err.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/interrupt.h>
@@ -370,6 +371,9 @@ static int qe_ep_bd_init(struct qe_udc *udc, unsigned char pipe_num)
/* alloc multi-ram for BD rings and set the ep parameters */
tmp_addr = cpm_muram_alloc(sizeof(struct qe_bd) * (bdring_len +
USB_BDRING_LEN_TX), QE_ALIGNMENT_OF_BD);
+ if (IS_ERR_VALUE(tmp_addr))
+ return -ENOMEM;
+
out_be16(&epparam->rbase, (u16)tmp_addr);
out_be16(&epparam->tbase, (u16)(tmp_addr +
(sizeof(struct qe_bd) * bdring_len)));
@@ -689,7 +693,7 @@ en_done2:
en_done1:
spin_unlock_irqrestore(&udc->lock, flags);
en_done:
- dev_dbg(udc->dev, "failed to initialize %s\n", ep->ep.name);
+ dev_err(udc->dev, "failed to initialize %s\n", ep->ep.name);
return -ENODEV;
}
@@ -2408,6 +2412,8 @@ static struct qe_udc __devinit *qe_udc_config(struct of_device *ofdev)
tmp_addr = cpm_muram_alloc((USB_MAX_ENDPOINTS *
sizeof(struct usb_ep_para)),
USB_EP_PARA_ALIGNMENT);
+ if (IS_ERR_VALUE(tmp_addr))
+ goto cleanup;
for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
out_be16(&usbpram->epptr[i], (u16)tmp_addr);
@@ -2513,7 +2519,7 @@ static int __devinit qe_udc_probe(struct of_device *ofdev,
/* Initialize the udc structure including QH member and other member */
udc_controller = qe_udc_config(ofdev);
if (!udc_controller) {
- dev_dbg(&ofdev->dev, "udc_controll is NULL\n");
+ dev_err(&ofdev->dev, "failed to initialize\n");
return -ENOMEM;
}
@@ -2568,7 +2574,7 @@ static int __devinit qe_udc_probe(struct of_device *ofdev,
/* create a buf for ZLP send, need to remain zeroed */
udc_controller->nullbuf = kzalloc(256, GFP_KERNEL);
if (udc_controller->nullbuf == NULL) {
- dev_dbg(udc_controller->dev, "cannot alloc nullbuf\n");
+ dev_err(udc_controller->dev, "cannot alloc nullbuf\n");
ret = -ENOMEM;
goto err3;
}
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 4e3107dd2f34..ec6d439a2aa5 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -110,7 +110,6 @@
#define gadget_is_at91(g) 0
#endif
-/* status unclear */
#ifdef CONFIG_USB_GADGET_IMX
#define gadget_is_imx(g) !strcmp("imx_udc", (g)->name)
#else
@@ -158,6 +157,11 @@
#define gadget_is_fsl_qe(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_CI13XXX
+#define gadget_is_ci13xxx(g) (!strcmp("ci13xxx_udc", (g)->name))
+#else
+#define gadget_is_ci13xxx(g) 0
+#endif
// CONFIG_USB_GADGET_SX2
// CONFIG_USB_GADGET_AU1X00
@@ -225,6 +229,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x21;
else if (gadget_is_fsl_qe(gadget))
return 0x22;
+ else if (gadget_is_ci13xxx(gadget))
+ return 0x23;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 60aa04847b18..63419c4d503c 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -1349,7 +1349,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
int retval;
if (!driver
- || driver->speed != USB_SPEED_FULL
+ || driver->speed < USB_SPEED_FULL
|| !driver->bind
|| !driver->disconnect
|| !driver->setup)
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
new file mode 100644
index 000000000000..cde8fdf15d5b
--- /dev/null
+++ b/drivers/usb/gadget/imx_udc.c
@@ -0,0 +1,1516 @@
+/*
+ * driver/usb/gadget/imx_udc.c
+ *
+ * Copyright (C) 2005 Mike Lee(eemike@gmail.com)
+ * Copyright (C) 2008 Darius Augulis <augulis.darius@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
+ * (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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <mach/usb.h>
+#include <mach/hardware.h>
+
+#include "imx_udc.h"
+
+static const char driver_name[] = "imx_udc";
+static const char ep0name[] = "ep0";
+
+void ep0_chg_stat(const char *label, struct imx_udc_struct *imx_usb,
+ enum ep0_state stat);
+
+/*******************************************************************************
+ * IMX UDC hardware related functions
+ *******************************************************************************
+ */
+
+void imx_udc_enable(struct imx_udc_struct *imx_usb)
+{
+ int temp = __raw_readl(imx_usb->base + USB_CTRL);
+ __raw_writel(temp | CTRL_FE_ENA | CTRL_AFE_ENA, imx_usb->base + USB_CTRL);
+ imx_usb->gadget.speed = USB_SPEED_FULL;
+}
+
+void imx_udc_disable(struct imx_udc_struct *imx_usb)
+{
+ int temp = __raw_readl(imx_usb->base + USB_CTRL);
+
+ __raw_writel(temp & ~(CTRL_FE_ENA | CTRL_AFE_ENA),
+ imx_usb->base + USB_CTRL);
+
+ ep0_chg_stat(__func__, imx_usb, EP0_IDLE);
+ imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
+}
+
+void imx_udc_reset(struct imx_udc_struct *imx_usb)
+{
+ int temp = __raw_readl(imx_usb->base + USB_ENAB);
+
+ /* set RST bit */
+ __raw_writel(temp | ENAB_RST, imx_usb->base + USB_ENAB);
+
+ /* wait RST bit to clear */
+ do {} while (__raw_readl(imx_usb->base + USB_ENAB) & ENAB_RST);
+
+ /* wait CFG bit to assert */
+ do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG));
+
+ /* udc module is now ready */
+}
+
+void imx_udc_config(struct imx_udc_struct *imx_usb)
+{
+ u8 ep_conf[5];
+ u8 i, j, cfg;
+ struct imx_ep_struct *imx_ep;
+
+ /* wait CFG bit to assert */
+ do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG));
+
+ /* Download the endpoint buffer for endpoint 0. */
+ for (j = 0; j < 5; j++) {
+ i = (j == 2 ? imx_usb->imx_ep[0].fifosize : 0x00);
+ __raw_writeb(i, imx_usb->base + USB_DDAT);
+ do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_BSY);
+ }
+
+ /* Download the endpoint buffers for endpoints 1-5.
+ * We specify two configurations, one interface
+ */
+ for (cfg = 1; cfg < 3; cfg++) {
+ for (i = 1; i < IMX_USB_NB_EP; i++) {
+ imx_ep = &imx_usb->imx_ep[i];
+ /* EP no | Config no */
+ ep_conf[0] = (i << 4) | (cfg << 2);
+ /* Type | Direction */
+ ep_conf[1] = (imx_ep->bmAttributes << 3) |
+ (EP_DIR(imx_ep) << 2);
+ /* Max packet size */
+ ep_conf[2] = imx_ep->fifosize;
+ /* TRXTYP */
+ ep_conf[3] = 0xC0;
+ /* FIFO no */
+ ep_conf[4] = i;
+
+ D_INI(imx_usb->dev,
+ "<%s> ep%d_conf[%d]:"
+ "[%02x-%02x-%02x-%02x-%02x]\n",
+ __func__, i, cfg,
+ ep_conf[0], ep_conf[1], ep_conf[2],
+ ep_conf[3], ep_conf[4]);
+
+ for (j = 0; j < 5; j++) {
+ __raw_writeb(ep_conf[j],
+ imx_usb->base + USB_DDAT);
+ do {} while (__raw_readl(imx_usb->base + USB_DADR)
+ & DADR_BSY);
+ }
+ }
+ }
+
+ /* wait CFG bit to clear */
+ do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG);
+}
+
+void imx_udc_init_irq(struct imx_udc_struct *imx_usb)
+{
+ int i;
+
+ /* Mask and clear all irqs */
+ __raw_writel(0xFFFFFFFF, imx_usb->base + USB_MASK);
+ __raw_writel(0xFFFFFFFF, imx_usb->base + USB_INTR);
+ for (i = 0; i < IMX_USB_NB_EP; i++) {
+ __raw_writel(0x1FF, imx_usb->base + USB_EP_MASK(i));
+ __raw_writel(0x1FF, imx_usb->base + USB_EP_INTR(i));
+ }
+
+ /* Enable USB irqs */
+ __raw_writel(INTR_MSOF | INTR_FRAME_MATCH, imx_usb->base + USB_MASK);
+
+ /* Enable EP0 irqs */
+ __raw_writel(0x1FF & ~(EPINTR_DEVREQ | EPINTR_MDEVREQ | EPINTR_EOT
+ | EPINTR_EOF | EPINTR_FIFO_EMPTY | EPINTR_FIFO_FULL),
+ imx_usb->base + USB_EP_MASK(0));
+}
+
+void imx_udc_init_ep(struct imx_udc_struct *imx_usb)
+{
+ int i, max, temp;
+ struct imx_ep_struct *imx_ep;
+ for (i = 0; i < IMX_USB_NB_EP; i++) {
+ imx_ep = &imx_usb->imx_ep[i];
+ switch (imx_ep->fifosize) {
+ case 8:
+ max = 0;
+ break;
+ case 16:
+ max = 1;
+ break;
+ case 32:
+ max = 2;
+ break;
+ case 64:
+ max = 3;
+ break;
+ default:
+ max = 1;
+ break;
+ }
+ temp = (EP_DIR(imx_ep) << 7) | (max << 5)
+ | (imx_ep->bmAttributes << 3);
+ __raw_writel(temp, imx_usb->base + USB_EP_STAT(i));
+ __raw_writel(temp | EPSTAT_FLUSH, imx_usb->base + USB_EP_STAT(i));
+ D_INI(imx_usb->dev, "<%s> ep%d_stat %08x\n", __func__, i,
+ __raw_readl(imx_usb->base + USB_EP_STAT(i)));
+ }
+}
+
+void imx_udc_init_fifo(struct imx_udc_struct *imx_usb)
+{
+ int i, temp;
+ struct imx_ep_struct *imx_ep;
+ for (i = 0; i < IMX_USB_NB_EP; i++) {
+ imx_ep = &imx_usb->imx_ep[i];
+
+ /* Fifo control */
+ temp = EP_DIR(imx_ep) ? 0x0B000000 : 0x0F000000;
+ __raw_writel(temp, imx_usb->base + USB_EP_FCTRL(i));
+ D_INI(imx_usb->dev, "<%s> ep%d_fctrl %08x\n", __func__, i,
+ __raw_readl(imx_usb->base + USB_EP_FCTRL(i)));
+
+ /* Fifo alarm */
+ temp = (i ? imx_ep->fifosize / 2 : 0);
+ __raw_writel(temp, imx_usb->base + USB_EP_FALRM(i));
+ D_INI(imx_usb->dev, "<%s> ep%d_falrm %08x\n", __func__, i,
+ __raw_readl(imx_usb->base + USB_EP_FALRM(i)));
+ }
+}
+
+static void imx_udc_init(struct imx_udc_struct *imx_usb)
+{
+ /* Reset UDC */
+ imx_udc_reset(imx_usb);
+
+ /* Download config to enpoint buffer */
+ imx_udc_config(imx_usb);
+
+ /* Setup interrups */
+ imx_udc_init_irq(imx_usb);
+
+ /* Setup endpoints */
+ imx_udc_init_ep(imx_usb);
+
+ /* Setup fifos */
+ imx_udc_init_fifo(imx_usb);
+}
+
+void imx_ep_irq_enable(struct imx_ep_struct *imx_ep)
+{
+
+ int i = EP_NO(imx_ep);
+
+ __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i));
+ __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i));
+ __raw_writel(0x1FF & ~(EPINTR_EOT | EPINTR_EOF),
+ imx_ep->imx_usb->base + USB_EP_MASK(i));
+}
+
+void imx_ep_irq_disable(struct imx_ep_struct *imx_ep)
+{
+
+ int i = EP_NO(imx_ep);
+
+ __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i));
+ __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i));
+}
+
+int imx_ep_empty(struct imx_ep_struct *imx_ep)
+{
+ struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
+
+ return __raw_readl(imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep)))
+ & FSTAT_EMPTY;
+}
+
+unsigned imx_fifo_bcount(struct imx_ep_struct *imx_ep)
+{
+ struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
+
+ return (__raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)))
+ & EPSTAT_BCOUNT) >> 16;
+}
+
+void imx_flush(struct imx_ep_struct *imx_ep)
+{
+ struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
+
+ int temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
+ __raw_writel(temp | EPSTAT_FLUSH,
+ imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
+}
+
+void imx_ep_stall(struct imx_ep_struct *imx_ep)
+{
+ struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
+ int temp, i;
+
+ D_ERR(imx_usb->dev, "<%s> Forced stall on %s\n", __func__, imx_ep->ep.name);
+
+ imx_flush(imx_ep);
+
+ /* Special care for ep0 */
+ if (EP_NO(imx_ep)) {
+ temp = __raw_readl(imx_usb->base + USB_CTRL);
+ __raw_writel(temp | CTRL_CMDOVER | CTRL_CMDERROR, imx_usb->base + USB_CTRL);
+ do { } while (__raw_readl(imx_usb->base + USB_CTRL) & CTRL_CMDOVER);
+ temp = __raw_readl(imx_usb->base + USB_CTRL);
+ __raw_writel(temp & ~CTRL_CMDERROR, imx_usb->base + USB_CTRL);
+ }
+ else {
+ temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
+ __raw_writel(temp | EPSTAT_STALL,
+ imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
+
+ for (i = 0; i < 100; i ++) {
+ temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
+ if (!temp & EPSTAT_STALL)
+ break;
+ udelay(20);
+ }
+ if (i == 50)
+ D_ERR(imx_usb->dev, "<%s> Non finished stall on %s\n",
+ __func__, imx_ep->ep.name);
+ }
+}
+
+static int imx_udc_get_frame(struct usb_gadget *_gadget)
+{
+ struct imx_udc_struct *imx_usb = container_of(_gadget,
+ struct imx_udc_struct, gadget);
+
+ return __raw_readl(imx_usb->base + USB_FRAME) & 0x7FF;
+}
+
+static int imx_udc_wakeup(struct usb_gadget *_gadget)
+{
+ return 0;
+}
+
+/*******************************************************************************
+ * USB request control functions
+ *******************************************************************************
+ */
+
+static void ep_add_request(struct imx_ep_struct *imx_ep, struct imx_request *req)
+{
+ if (unlikely(!req))
+ return;
+
+ req->in_use = 1;
+ list_add_tail(&req->queue, &imx_ep->queue);
+}
+
+static void ep_del_request(struct imx_ep_struct *imx_ep, struct imx_request *req)
+{
+ if (unlikely(!req))
+ return;
+
+ list_del_init(&req->queue);
+ req->in_use = 0;
+}
+
+static void done(struct imx_ep_struct *imx_ep, struct imx_request *req, int status)
+{
+ ep_del_request(imx_ep, req);
+
+ if (likely(req->req.status == -EINPROGRESS))
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ if (status && status != -ESHUTDOWN)
+ D_ERR(imx_ep->imx_usb->dev,
+ "<%s> complete %s req %p stat %d len %u/%u\n", __func__,
+ imx_ep->ep.name, &req->req, status,
+ req->req.actual, req->req.length);
+
+ req->req.complete(&imx_ep->ep, &req->req);
+}
+
+static void nuke(struct imx_ep_struct *imx_ep, int status)
+{
+ struct imx_request *req;
+
+ while (!list_empty(&imx_ep->queue)) {
+ req = list_entry(imx_ep->queue.next, struct imx_request, queue);
+ done(imx_ep, req, status);
+ }
+}
+
+/*******************************************************************************
+ * Data tansfer over USB functions
+ *******************************************************************************
+ */
+static int read_packet(struct imx_ep_struct *imx_ep, struct imx_request *req)
+{
+ u8 *buf;
+ int bytes_ep, bufferspace, count, i;
+
+ bytes_ep = imx_fifo_bcount(imx_ep);
+ bufferspace = req->req.length - req->req.actual;
+
+ buf = req->req.buf + req->req.actual;
+ prefetchw(buf);
+
+ if (unlikely(imx_ep_empty(imx_ep)))
+ count = 0; /* zlp */
+ else
+ count = min(bytes_ep, bufferspace);
+
+ for (i = count; i > 0; i--)
+ *buf++ = __raw_readb(imx_ep->imx_usb->base
+ + USB_EP_FDAT0(EP_NO(imx_ep)));
+ req->req.actual += count;
+
+ return count;
+}
+
+static int write_packet(struct imx_ep_struct *imx_ep, struct imx_request *req)
+{
+ u8 *buf;
+ int length, count, temp;
+
+ buf = req->req.buf + req->req.actual;
+ prefetch(buf);
+
+ length = min(req->req.length - req->req.actual, (u32)imx_ep->fifosize);
+
+ if (imx_fifo_bcount(imx_ep) + length > imx_ep->fifosize) {
+ D_TRX(imx_ep->imx_usb->dev, "<%s> packet overfill %s fifo\n",
+ __func__, imx_ep->ep.name);
+ return -1;
+ }
+
+ req->req.actual += length;
+ count = length;
+
+ if (!count && req->req.zero) { /* zlp */
+ temp = __raw_readl(imx_ep->imx_usb->base
+ + USB_EP_STAT(EP_NO(imx_ep)));
+ __raw_writel(temp | EPSTAT_ZLPS, imx_ep->imx_usb->base
+ + USB_EP_STAT(EP_NO(imx_ep)));
+ D_TRX(imx_ep->imx_usb->dev, "<%s> zero packet\n", __func__);
+ return 0;
+ }
+
+ while (count--) {
+ if (count == 0) { /* last byte */
+ temp = __raw_readl(imx_ep->imx_usb->base
+ + USB_EP_FCTRL(EP_NO(imx_ep)));
+ __raw_writel(temp | FCTRL_WFR, imx_ep->imx_usb->base
+ + USB_EP_FCTRL(EP_NO(imx_ep)));
+ }
+ __raw_writeb(*buf++,
+ imx_ep->imx_usb->base + USB_EP_FDAT0(EP_NO(imx_ep)));
+ }
+
+ return length;
+}
+
+static int read_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req)
+{
+ int bytes = 0,
+ count,
+ completed = 0;
+
+ while (__raw_readl(imx_ep->imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep)))
+ & FSTAT_FR) {
+ count = read_packet(imx_ep, req);
+ bytes += count;
+
+ completed = (count != imx_ep->fifosize);
+ if (completed || req->req.actual == req->req.length) {
+ completed = 1;
+ break;
+ }
+ }
+
+ if (completed || !req->req.length) {
+ done(imx_ep, req, 0);
+ D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n",
+ __func__, imx_ep->ep.name, req,
+ completed ? "completed" : "not completed");
+ if (!EP_NO(imx_ep))
+ ep0_chg_stat(__func__, imx_ep->imx_usb, EP0_IDLE);
+ }
+
+ D_TRX(imx_ep->imx_usb->dev, "<%s> bytes read: %d\n", __func__, bytes);
+
+ return completed;
+}
+
+static int write_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req)
+{
+ int bytes = 0,
+ count,
+ completed = 0;
+
+ while (!completed) {
+ count = write_packet(imx_ep, req);
+ if (count < 0)
+ break; /* busy */
+ bytes += count;
+
+ /* last packet "must be" short (or a zlp) */
+ completed = (count != imx_ep->fifosize);
+
+ if (unlikely(completed)) {
+ done(imx_ep, req, 0);
+ D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n",
+ __func__, imx_ep->ep.name, req,
+ completed ? "completed" : "not completed");
+ if (!EP_NO(imx_ep))
+ ep0_chg_stat(__func__, imx_ep->imx_usb, EP0_IDLE);
+ }
+ }
+
+ D_TRX(imx_ep->imx_usb->dev, "<%s> bytes sent: %d\n", __func__, bytes);
+
+ return completed;
+}
+
+/*******************************************************************************
+ * Endpoint handlers
+ *******************************************************************************
+ */
+static int handle_ep(struct imx_ep_struct *imx_ep)
+{
+ struct imx_request *req;
+ int completed = 0;
+
+ do {
+ if (!list_empty(&imx_ep->queue))
+ req = list_entry(imx_ep->queue.next,
+ struct imx_request, queue);
+ else {
+ D_REQ(imx_ep->imx_usb->dev, "<%s> no request on %s\n",
+ __func__, imx_ep->ep.name);
+ return 0;
+ }
+
+ if (EP_DIR(imx_ep)) /* to host */
+ completed = write_fifo(imx_ep, req);
+ else /* to device */
+ completed = read_fifo(imx_ep, req);
+
+ dump_ep_stat(__func__, imx_ep);
+
+ } while (completed);
+
+ return 0;
+}
+
+static int handle_ep0(struct imx_ep_struct *imx_ep)
+{
+ struct imx_request *req = NULL;
+ int ret = 0;
+
+ if (!list_empty(&imx_ep->queue))
+ req = list_entry(imx_ep->queue.next, struct imx_request, queue);
+
+ if (req) {
+ switch (imx_ep->imx_usb->ep0state) {
+
+ case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR */
+ write_fifo(imx_ep, req);
+ break;
+ case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR */
+ read_fifo(imx_ep, req);
+ break;
+ default:
+ D_EP0(imx_ep->imx_usb->dev,
+ "<%s> ep0 i/o, odd state %d\n",
+ __func__, imx_ep->imx_usb->ep0state);
+ ep_del_request(imx_ep, req);
+ ret = -EL2HLT;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static void handle_ep0_devreq(struct imx_udc_struct *imx_usb)
+{
+ struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0];
+ union {
+ struct usb_ctrlrequest r;
+ u8 raw[8];
+ u32 word[2];
+ } u;
+ int temp, i;
+
+ nuke(imx_ep, -EPROTO);
+
+ /* read SETUP packet */
+ for (i = 0; i < 2; i++) {
+ if (imx_ep_empty(imx_ep)) {
+ D_ERR(imx_usb->dev,
+ "<%s> no setup packet received\n", __func__);
+ goto stall;
+ }
+ u.word[i] = __raw_readl(imx_usb->base + USB_EP_FDAT(EP_NO(imx_ep)));
+ }
+
+ temp = imx_ep_empty(imx_ep);
+ while (!imx_ep_empty(imx_ep)) {
+ i = __raw_readl(imx_usb->base + USB_EP_FDAT(EP_NO(imx_ep)));
+ D_ERR(imx_usb->dev,
+ "<%s> wrong to have extra bytes for setup : 0x%08x\n",
+ __func__, i);
+ }
+ if (!temp)
+ goto stall;
+
+ le16_to_cpus(&u.r.wValue);
+ le16_to_cpus(&u.r.wIndex);
+ le16_to_cpus(&u.r.wLength);
+
+ D_REQ(imx_usb->dev, "<%s> SETUP %02x.%02x v%04x i%04x l%04x\n",
+ __func__, u.r.bRequestType, u.r.bRequest,
+ u.r.wValue, u.r.wIndex, u.r.wLength);
+
+ if (imx_usb->set_config) {
+ /* NACK the host by using CMDOVER */
+ temp = __raw_readl(imx_usb->base + USB_CTRL);
+ __raw_writel(temp | CTRL_CMDOVER, imx_usb->base + USB_CTRL);
+
+ D_ERR(imx_usb->dev,
+ "<%s> set config req is pending, NACK the host\n",
+ __func__);
+ return;
+ }
+
+ if (u.r.bRequestType & USB_DIR_IN)
+ ep0_chg_stat(__func__, imx_usb, EP0_IN_DATA_PHASE);
+ else
+ ep0_chg_stat(__func__, imx_usb, EP0_OUT_DATA_PHASE);
+
+ i = imx_usb->driver->setup(&imx_usb->gadget, &u.r);
+ if (i < 0) {
+ D_ERR(imx_usb->dev, "<%s> device setup error %d\n",
+ __func__, i);
+ goto stall;
+ }
+
+ return;
+stall:
+ D_ERR(imx_usb->dev, "<%s> protocol STALL\n", __func__);
+ imx_ep_stall(imx_ep);
+ ep0_chg_stat(__func__, imx_usb, EP0_STALL);
+ return;
+}
+
+/*******************************************************************************
+ * USB gadget callback functions
+ *******************************************************************************
+ */
+
+static int imx_ep_enable(struct usb_ep *usb_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct imx_ep_struct *imx_ep = container_of(usb_ep,
+ struct imx_ep_struct, ep);
+ struct imx_udc_struct *imx_usb = imx_ep->imx_usb;
+ unsigned long flags;
+
+ if (!usb_ep
+ || !desc
+ || !EP_NO(imx_ep)
+ || desc->bDescriptorType != USB_DT_ENDPOINT
+ || imx_ep->bEndpointAddress != desc->bEndpointAddress) {
+ D_ERR(imx_usb->dev,
+ "<%s> bad ep or descriptor\n", __func__);
+ return -EINVAL;
+ }
+
+ if (imx_ep->bmAttributes != desc->bmAttributes) {
+ D_ERR(imx_usb->dev,
+ "<%s> %s type mismatch\n", __func__, usb_ep->name);
+ return -EINVAL;
+ }
+
+ if (imx_ep->fifosize < le16_to_cpu(desc->wMaxPacketSize)) {
+ D_ERR(imx_usb->dev,
+ "<%s> bad %s maxpacket\n", __func__, usb_ep->name);
+ return -ERANGE;
+ }
+
+ if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) {
+ D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__);
+ return -ESHUTDOWN;
+ }
+
+ local_irq_save(flags);
+
+ imx_ep->stopped = 0;
+ imx_flush(imx_ep);
+ imx_ep_irq_enable(imx_ep);
+
+ local_irq_restore(flags);
+
+ D_EPX(imx_usb->dev, "<%s> ENABLED %s\n", __func__, usb_ep->name);
+ return 0;
+}
+
+static int imx_ep_disable(struct usb_ep *usb_ep)
+{
+ struct imx_ep_struct *imx_ep = container_of(usb_ep,
+ struct imx_ep_struct, ep);
+ unsigned long flags;
+
+ if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) {
+ D_ERR(imx_ep->imx_usb->dev, "<%s> %s can not be disabled\n",
+ __func__, usb_ep ? imx_ep->ep.name : NULL);
+ return -EINVAL;
+ }
+
+ local_irq_save(flags);
+
+ imx_ep->stopped = 1;
+ nuke(imx_ep, -ESHUTDOWN);
+ imx_flush(imx_ep);
+ imx_ep_irq_disable(imx_ep);
+
+ local_irq_restore(flags);
+
+ D_EPX(imx_ep->imx_usb->dev,
+ "<%s> DISABLED %s\n", __func__, usb_ep->name);
+ return 0;
+}
+
+static struct usb_request *imx_ep_alloc_request
+ (struct usb_ep *usb_ep, gfp_t gfp_flags)
+{
+ struct imx_request *req;
+
+ req = kzalloc(sizeof *req, gfp_flags);
+ if (!req || !usb_ep)
+ return 0;
+
+ INIT_LIST_HEAD(&req->queue);
+ req->in_use = 0;
+
+ return &req->req;
+}
+
+static void imx_ep_free_request
+ (struct usb_ep *usb_ep, struct usb_request *usb_req)
+{
+ struct imx_request *req;
+
+ req = container_of(usb_req, struct imx_request, req);
+ WARN_ON(!list_empty(&req->queue));
+ kfree(req);
+}
+
+static int imx_ep_queue
+ (struct usb_ep *usb_ep, struct usb_request *usb_req, gfp_t gfp_flags)
+{
+ struct imx_ep_struct *imx_ep;
+ struct imx_udc_struct *imx_usb;
+ struct imx_request *req;
+ unsigned long flags;
+ int ret = 0;
+
+ imx_ep = container_of(usb_ep, struct imx_ep_struct, ep);
+ imx_usb = imx_ep->imx_usb;
+ req = container_of(usb_req, struct imx_request, req);
+
+ /*
+ Special care on IMX udc.
+ Ignore enqueue when after set configuration from the
+ host. This assume all gadget drivers reply set
+ configuration with the next ep0 req enqueue.
+ */
+ if (imx_usb->set_config && !EP_NO(imx_ep)) {
+ imx_usb->set_config = 0;
+ D_EPX(imx_usb->dev,
+ "<%s> gadget reply set config\n", __func__);
+ return 0;
+ }
+
+ if (unlikely(!usb_req || !req || !usb_req->complete || !usb_req->buf)) {
+ D_ERR(imx_usb->dev, "<%s> bad params\n", __func__);
+ return -EINVAL;
+ }
+
+ if (unlikely(!usb_ep || !imx_ep)) {
+ D_ERR(imx_usb->dev, "<%s> bad ep\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) {
+ D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__);
+ return -ESHUTDOWN;
+ }
+
+ local_irq_save(flags);
+
+ /* Debug */
+ D_REQ(imx_usb->dev, "<%s> ep%d %s request for [%d] bytes\n",
+ __func__, EP_NO(imx_ep),
+ ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state == EP0_IN_DATA_PHASE)
+ || (EP_NO(imx_ep) && EP_DIR(imx_ep))) ? "IN" : "OUT", usb_req->length);
+ dump_req(__func__, imx_ep, usb_req);
+
+ if (imx_ep->stopped) {
+ usb_req->status = -ESHUTDOWN;
+ ret = -ESHUTDOWN;
+ goto out;
+ }
+
+ if (req->in_use) {
+ D_ERR(imx_usb->dev,
+ "<%s> refusing to queue req %p (already queued)\n",
+ __func__, req);
+ goto out;
+ }
+
+ usb_req->status = -EINPROGRESS;
+ usb_req->actual = 0;
+
+ ep_add_request(imx_ep, req);
+
+ if (!EP_NO(imx_ep))
+ ret = handle_ep0(imx_ep);
+ else
+ ret = handle_ep(imx_ep);
+out:
+ local_irq_restore(flags);
+ return ret;
+}
+
+static int imx_ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
+{
+
+ struct imx_ep_struct *imx_ep = container_of
+ (usb_ep, struct imx_ep_struct, ep);
+ struct imx_request *req;
+ unsigned long flags;
+
+ if (unlikely(!usb_ep || !EP_NO(imx_ep))) {
+ D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
+ return -EINVAL;
+ }
+
+ local_irq_save(flags);
+
+ /* make sure it's actually queued on this endpoint */
+ list_for_each_entry(req, &imx_ep->queue, queue) {
+ if (&req->req == usb_req)
+ break;
+ }
+ if (&req->req != usb_req) {
+ local_irq_restore(flags);
+ return -EINVAL;
+ }
+
+ done(imx_ep, req, -ECONNRESET);
+
+ local_irq_restore(flags);
+ return 0;
+}
+
+static int imx_ep_set_halt(struct usb_ep *usb_ep, int value)
+{
+ struct imx_ep_struct *imx_ep = container_of
+ (usb_ep, struct imx_ep_struct, ep);
+ unsigned long flags;
+
+ if (unlikely(!usb_ep || !EP_NO(imx_ep))) {
+ D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
+ return -EINVAL;
+ }
+
+ local_irq_save(flags);
+
+ if ((imx_ep->bEndpointAddress & USB_DIR_IN)
+ && !list_empty(&imx_ep->queue)) {
+ local_irq_restore(flags);
+ return -EAGAIN;
+ }
+
+ imx_ep_stall(imx_ep);
+
+ local_irq_restore(flags);
+
+ D_EPX(imx_ep->imx_usb->dev, "<%s> %s halt\n", __func__, usb_ep->name);
+ return 0;
+}
+
+static int imx_ep_fifo_status(struct usb_ep *usb_ep)
+{
+ struct imx_ep_struct *imx_ep = container_of
+ (usb_ep, struct imx_ep_struct, ep);
+
+ if (!usb_ep) {
+ D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
+ return -ENODEV;
+ }
+
+ if (imx_ep->imx_usb->gadget.speed == USB_SPEED_UNKNOWN)
+ return 0;
+ else
+ return imx_fifo_bcount(imx_ep);
+}
+
+static void imx_ep_fifo_flush(struct usb_ep *usb_ep)
+{
+ struct imx_ep_struct *imx_ep = container_of
+ (usb_ep, struct imx_ep_struct, ep);
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) {
+ D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__);
+ local_irq_restore(flags);
+ return;
+ }
+
+ /* toggle and halt bits stay unchanged */
+ imx_flush(imx_ep);
+
+ local_irq_restore(flags);
+}
+
+static struct usb_ep_ops imx_ep_ops = {
+ .enable = imx_ep_enable,
+ .disable = imx_ep_disable,
+
+ .alloc_request = imx_ep_alloc_request,
+ .free_request = imx_ep_free_request,
+
+ .queue = imx_ep_queue,
+ .dequeue = imx_ep_dequeue,
+
+ .set_halt = imx_ep_set_halt,
+ .fifo_status = imx_ep_fifo_status,
+ .fifo_flush = imx_ep_fifo_flush,
+};
+
+/*******************************************************************************
+ * USB endpoint control functions
+ *******************************************************************************
+ */
+
+void ep0_chg_stat(const char *label,
+ struct imx_udc_struct *imx_usb, enum ep0_state stat)
+{
+ D_EP0(imx_usb->dev, "<%s> from %15s to %15s\n",
+ label, state_name[imx_usb->ep0state], state_name[stat]);
+
+ if (imx_usb->ep0state == stat)
+ return;
+
+ imx_usb->ep0state = stat;
+}
+
+static void usb_init_data(struct imx_udc_struct *imx_usb)
+{
+ struct imx_ep_struct *imx_ep;
+ u8 i;
+
+ /* device/ep0 records init */
+ INIT_LIST_HEAD(&imx_usb->gadget.ep_list);
+ INIT_LIST_HEAD(&imx_usb->gadget.ep0->ep_list);
+ ep0_chg_stat(__func__, imx_usb, EP0_IDLE);
+
+ /* basic endpoint records init */
+ for (i = 0; i < IMX_USB_NB_EP; i++) {
+ imx_ep = &imx_usb->imx_ep[i];
+
+ if (i) {
+ list_add_tail(&imx_ep->ep.ep_list,
+ &imx_usb->gadget.ep_list);
+ imx_ep->stopped = 1;
+ } else
+ imx_ep->stopped = 0;
+
+ INIT_LIST_HEAD(&imx_ep->queue);
+ }
+}
+
+static void udc_stop_activity(struct imx_udc_struct *imx_usb,
+ struct usb_gadget_driver *driver)
+{
+ struct imx_ep_struct *imx_ep;
+ int i;
+
+ if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN)
+ driver = NULL;
+
+ /* prevent new request submissions, kill any outstanding requests */
+ for (i = 1; i < IMX_USB_NB_EP; i++) {
+ imx_ep = &imx_usb->imx_ep[i];
+ imx_flush(imx_ep);
+ imx_ep->stopped = 1;
+ imx_ep_irq_disable(imx_ep);
+ nuke(imx_ep, -ESHUTDOWN);
+ }
+
+ imx_usb->cfg = 0;
+ imx_usb->intf = 0;
+ imx_usb->alt = 0;
+
+ if (driver)
+ driver->disconnect(&imx_usb->gadget);
+}
+
+/*******************************************************************************
+ * Interrupt handlers
+ *******************************************************************************
+ */
+
+static irqreturn_t imx_udc_irq(int irq, void *dev)
+{
+ struct imx_udc_struct *imx_usb = dev;
+ struct usb_ctrlrequest u;
+ int temp, cfg, intf, alt;
+ int intr = __raw_readl(imx_usb->base + USB_INTR);
+
+ if (intr & (INTR_WAKEUP | INTR_SUSPEND | INTR_RESUME | INTR_RESET_START
+ | INTR_RESET_STOP | INTR_CFG_CHG)) {
+ dump_intr(__func__, intr, imx_usb->dev);
+ dump_usb_stat(__func__, imx_usb);
+ }
+
+ if (!imx_usb->driver) {
+ /*imx_udc_disable(imx_usb);*/
+ goto end_irq;
+ }
+
+ if (intr & INTR_WAKEUP) {
+ if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN
+ && imx_usb->driver && imx_usb->driver->resume)
+ imx_usb->driver->resume(&imx_usb->gadget);
+ imx_usb->set_config = 0;
+ imx_usb->gadget.speed = USB_SPEED_FULL;
+ }
+
+ if (intr & INTR_SUSPEND) {
+ if (imx_usb->gadget.speed != USB_SPEED_UNKNOWN
+ && imx_usb->driver && imx_usb->driver->suspend)
+ imx_usb->driver->suspend(&imx_usb->gadget);
+ imx_usb->set_config = 0;
+ imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
+ }
+
+ if (intr & INTR_RESET_START) {
+ __raw_writel(intr, imx_usb->base + USB_INTR);
+ udc_stop_activity(imx_usb, imx_usb->driver);
+ imx_usb->set_config = 0;
+ imx_usb->gadget.speed = USB_SPEED_UNKNOWN;
+ }
+
+ if (intr & INTR_RESET_STOP)
+ imx_usb->gadget.speed = USB_SPEED_FULL;
+
+ if (intr & INTR_CFG_CHG) {
+ __raw_writel(INTR_CFG_CHG, imx_usb->base + USB_INTR);
+ temp = __raw_readl(imx_usb->base + USB_STAT);
+ cfg = (temp & STAT_CFG) >> 5;
+ intf = (temp & STAT_INTF) >> 3;
+ alt = temp & STAT_ALTSET;
+
+ D_REQ(imx_usb->dev,
+ "<%s> orig config C=%d, I=%d, A=%d / "
+ "req config C=%d, I=%d, A=%d\n",
+ __func__, imx_usb->cfg, imx_usb->intf, imx_usb->alt,
+ cfg, intf, alt);
+
+ if (cfg != 1 && cfg != 2)
+ goto end_irq;
+
+ imx_usb->set_config = 0;
+
+ /* Config setup */
+ if (imx_usb->cfg != cfg) {
+ D_REQ(imx_usb->dev, "<%s> Change config start\n",__func__);
+ u.bRequest = USB_REQ_SET_CONFIGURATION;
+ u.bRequestType = USB_DIR_OUT |
+ USB_TYPE_STANDARD |
+ USB_RECIP_DEVICE;
+ u.wValue = cfg;
+ u.wIndex = 0;
+ u.wLength = 0;
+ imx_usb->cfg = cfg;
+ imx_usb->set_config = 1;
+ imx_usb->driver->setup(&imx_usb->gadget, &u);
+ imx_usb->set_config = 0;
+ D_REQ(imx_usb->dev, "<%s> Change config done\n",__func__);
+
+ }
+ if (imx_usb->intf != intf || imx_usb->alt != alt) {
+ D_REQ(imx_usb->dev, "<%s> Change interface start\n",__func__);
+ u.bRequest = USB_REQ_SET_INTERFACE;
+ u.bRequestType = USB_DIR_OUT |
+ USB_TYPE_STANDARD |
+ USB_RECIP_INTERFACE;
+ u.wValue = alt;
+ u.wIndex = intf;
+ u.wLength = 0;
+ imx_usb->intf = intf;
+ imx_usb->alt = alt;
+ imx_usb->set_config = 1;
+ imx_usb->driver->setup(&imx_usb->gadget, &u);
+ imx_usb->set_config = 0;
+ D_REQ(imx_usb->dev, "<%s> Change interface done\n",__func__);
+ }
+ }
+
+ if (intr & INTR_SOF) {
+ if (imx_usb->ep0state == EP0_IDLE) {
+ temp = __raw_readl(imx_usb->base + USB_CTRL);
+ __raw_writel(temp | CTRL_CMDOVER, imx_usb->base + USB_CTRL);
+ }
+ }
+
+end_irq:
+ __raw_writel(intr, imx_usb->base + USB_INTR);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t imx_udc_ctrl_irq(int irq, void *dev)
+{
+ struct imx_udc_struct *imx_usb = dev;
+ int intr = __raw_readl(imx_usb->base + USB_EP_INTR(0));
+
+ dump_ep_intr(__func__, 0, intr, imx_usb->dev);
+
+ if (!imx_usb->driver) {
+ __raw_writel(intr, imx_usb->base + USB_EP_INTR(0));
+ return IRQ_HANDLED;
+ }
+
+ /* DEVREQ IRQ has highest priority */
+ if (intr & (EPINTR_DEVREQ | EPINTR_MDEVREQ))
+ handle_ep0_devreq(imx_usb);
+ /* Seem i.MX is missing EOF interrupt sometimes.
+ * Therefore we monitor both EOF and FIFO_EMPTY interrups
+ * when transmiting, and both EOF and FIFO_FULL when
+ * receiving data.
+ */
+ else if (intr & (EPINTR_EOF | EPINTR_FIFO_EMPTY | EPINTR_FIFO_FULL))
+ handle_ep0(&imx_usb->imx_ep[0]);
+
+ __raw_writel(intr, imx_usb->base + USB_EP_INTR(0));
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t imx_udc_bulk_irq(int irq, void *dev)
+{
+ struct imx_udc_struct *imx_usb = dev;
+ struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[irq - USBD_INT0];
+ int intr = __raw_readl(imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
+
+ dump_ep_intr(__func__, irq - USBD_INT0, intr, imx_usb->dev);
+
+ if (!imx_usb->driver) {
+ __raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
+ return IRQ_HANDLED;
+ }
+
+ handle_ep(imx_ep);
+
+ __raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
+
+ return IRQ_HANDLED;
+}
+
+irq_handler_t intr_handler(int i)
+{
+ switch (i) {
+ case 0:
+ return imx_udc_ctrl_irq;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ return imx_udc_bulk_irq;
+ default:
+ return imx_udc_irq;
+ }
+}
+
+/*******************************************************************************
+ * Static defined IMX UDC structure
+ *******************************************************************************
+ */
+
+static const struct usb_gadget_ops imx_udc_ops = {
+ .get_frame = imx_udc_get_frame,
+ .wakeup = imx_udc_wakeup,
+};
+
+static struct imx_udc_struct controller = {
+ .gadget = {
+ .ops = &imx_udc_ops,
+ .ep0 = &controller.imx_ep[0].ep,
+ .name = driver_name,
+ .dev = {
+ .bus_id = "gadget",
+ },
+ },
+
+ .imx_ep[0] = {
+ .ep = {
+ .name = ep0name,
+ .ops = &imx_ep_ops,
+ .maxpacket = 32,
+ },
+ .imx_usb = &controller,
+ .fifosize = 32,
+ .bEndpointAddress = 0,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ },
+ .imx_ep[1] = {
+ .ep = {
+ .name = "ep1in-bulk",
+ .ops = &imx_ep_ops,
+ .maxpacket = 64,
+ },
+ .imx_usb = &controller,
+ .fifosize = 64,
+ .bEndpointAddress = USB_DIR_IN | 1,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ .imx_ep[2] = {
+ .ep = {
+ .name = "ep2out-bulk",
+ .ops = &imx_ep_ops,
+ .maxpacket = 64,
+ },
+ .imx_usb = &controller,
+ .fifosize = 64,
+ .bEndpointAddress = USB_DIR_OUT | 2,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ .imx_ep[3] = {
+ .ep = {
+ .name = "ep3out-bulk",
+ .ops = &imx_ep_ops,
+ .maxpacket = 32,
+ },
+ .imx_usb = &controller,
+ .fifosize = 32,
+ .bEndpointAddress = USB_DIR_OUT | 3,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ .imx_ep[4] = {
+ .ep = {
+ .name = "ep4in-int",
+ .ops = &imx_ep_ops,
+ .maxpacket = 32,
+ },
+ .imx_usb = &controller,
+ .fifosize = 32,
+ .bEndpointAddress = USB_DIR_IN | 4,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ },
+ .imx_ep[5] = {
+ .ep = {
+ .name = "ep5out-int",
+ .ops = &imx_ep_ops,
+ .maxpacket = 32,
+ },
+ .imx_usb = &controller,
+ .fifosize = 32,
+ .bEndpointAddress = USB_DIR_OUT | 5,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ },
+};
+
+/*******************************************************************************
+ * USB gadged driver functions
+ *******************************************************************************
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct imx_udc_struct *imx_usb = &controller;
+ int retval;
+
+ if (!driver
+ || driver->speed < USB_SPEED_FULL
+ || !driver->bind
+ || !driver->disconnect
+ || !driver->setup)
+ return -EINVAL;
+ if (!imx_usb)
+ return -ENODEV;
+ if (imx_usb->driver)
+ return -EBUSY;
+
+ /* first hook up the driver ... */
+ imx_usb->driver = driver;
+ imx_usb->gadget.dev.driver = &driver->driver;
+
+ retval = device_add(&imx_usb->gadget.dev);
+ if (retval)
+ goto fail;
+ retval = driver->bind(&imx_usb->gadget);
+ if (retval) {
+ D_ERR(imx_usb->dev, "<%s> bind to driver %s --> error %d\n",
+ __func__, driver->driver.name, retval);
+ device_del(&imx_usb->gadget.dev);
+
+ goto fail;
+ }
+
+ D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n",
+ __func__, driver->driver.name);
+
+ imx_udc_enable(imx_usb);
+
+ return 0;
+fail:
+ imx_usb->driver = NULL;
+ imx_usb->gadget.dev.driver = NULL;
+ return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct imx_udc_struct *imx_usb = &controller;
+
+ if (!imx_usb)
+ return -ENODEV;
+ if (!driver || driver != imx_usb->driver || !driver->unbind)
+ return -EINVAL;
+
+ udc_stop_activity(imx_usb, driver);
+ imx_udc_disable(imx_usb);
+
+ driver->unbind(&imx_usb->gadget);
+ imx_usb->gadget.dev.driver = NULL;
+ imx_usb->driver = NULL;
+
+ device_del(&imx_usb->gadget.dev);
+
+ D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n",
+ __func__, driver->driver.name);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/*******************************************************************************
+ * Module functions
+ *******************************************************************************
+ */
+
+static int __init imx_udc_probe(struct platform_device *pdev)
+{
+ struct imx_udc_struct *imx_usb = &controller;
+ struct resource *res;
+ struct imxusb_platform_data *pdata;
+ struct clk *clk;
+ void __iomem *base;
+ int ret = 0;
+ int i, res_size;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "can't get device resources\n");
+ return -ENODEV;
+ }
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "driver needs platform data\n");
+ return -ENODEV;
+ }
+
+ res_size = res->end - res->start + 1;
+ if (!request_mem_region(res->start, res_size, res->name)) {
+ dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
+ res_size, res->start);
+ return -ENOMEM;
+ }
+
+ if (pdata->init) {
+ ret = pdata->init(&pdev->dev);
+ if (ret)
+ goto fail0;
+ }
+
+ base = ioremap(res->start, res_size);
+ if (!base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -EIO;
+ goto fail1;
+ }
+
+ clk = clk_get(NULL, "usbd_clk");
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ dev_err(&pdev->dev, "can't get USB clock\n");
+ goto fail2;
+ }
+ clk_enable(clk);
+
+ if (clk_get_rate(clk) != 48000000) {
+ D_INI(&pdev->dev,
+ "Bad USB clock (%d Hz), changing to 48000000 Hz\n",
+ (int)clk_get_rate(clk));
+ if (clk_set_rate(clk, 48000000)) {
+ dev_err(&pdev->dev,
+ "Unable to set correct USB clock (48MHz)\n");
+ ret = -EIO;
+ goto fail3;
+ }
+ }
+
+ for (i = 0; i < IMX_USB_NB_EP + 1; i++) {
+ imx_usb->usbd_int[i] = platform_get_irq(pdev, i);
+ if (imx_usb->usbd_int[i] < 0) {
+ dev_err(&pdev->dev, "can't get irq number\n");
+ ret = -ENODEV;
+ goto fail3;
+ }
+ }
+
+ for (i = 0; i < IMX_USB_NB_EP + 1; i++) {
+ ret = request_irq(imx_usb->usbd_int[i], intr_handler(i),
+ IRQF_DISABLED, driver_name, imx_usb);
+ if (ret) {
+ dev_err(&pdev->dev, "can't get irq %i, err %d\n",
+ imx_usb->usbd_int[i], ret);
+ for (--i; i >= 0; i--)
+ free_irq(imx_usb->usbd_int[i], imx_usb);
+ goto fail3;
+ }
+ }
+
+ imx_usb->res = res;
+ imx_usb->base = base;
+ imx_usb->clk = clk;
+ imx_usb->dev = &pdev->dev;
+
+ device_initialize(&imx_usb->gadget.dev);
+
+ imx_usb->gadget.dev.parent = &pdev->dev;
+ imx_usb->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+ platform_set_drvdata(pdev, imx_usb);
+
+ usb_init_data(imx_usb);
+ imx_udc_init(imx_usb);
+
+ return 0;
+
+fail3:
+ clk_put(clk);
+ clk_disable(clk);
+fail2:
+ iounmap(base);
+fail1:
+ if (pdata->exit)
+ pdata->exit(&pdev->dev);
+fail0:
+ release_mem_region(res->start, res_size);
+ return ret;
+}
+
+static int __exit imx_udc_remove(struct platform_device *pdev)
+{
+ struct imx_udc_struct *imx_usb = platform_get_drvdata(pdev);
+ struct imxusb_platform_data *pdata = pdev->dev.platform_data;
+ int i;
+
+ imx_udc_disable(imx_usb);
+
+ for (i = 0; i < IMX_USB_NB_EP + 1; i++)
+ free_irq(imx_usb->usbd_int[i], imx_usb);
+
+ clk_put(imx_usb->clk);
+ clk_disable(imx_usb->clk);
+ iounmap(imx_usb->base);
+
+ release_mem_region(imx_usb->res->start,
+ imx_usb->res->end - imx_usb->res->start + 1);
+
+ if (pdata->exit)
+ pdata->exit(&pdev->dev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PM
+#define imx_udc_suspend NULL
+#define imx_udc_resume NULL
+#else
+#define imx_udc_suspend NULL
+#define imx_udc_resume NULL
+#endif
+
+/*----------------------------------------------------------------------------*/
+
+static struct platform_driver udc_driver = {
+ .driver = {
+ .name = driver_name,
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(imx_udc_remove),
+ .suspend = imx_udc_suspend,
+ .resume = imx_udc_resume,
+};
+
+static int __init udc_init(void)
+{
+ return platform_driver_probe(&udc_driver, imx_udc_probe);
+}
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION("IMX USB Device Controller driver");
+MODULE_AUTHOR("Darius Augulis <augulis.darius@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx_udc");
diff --git a/drivers/usb/gadget/imx_udc.h b/drivers/usb/gadget/imx_udc.h
new file mode 100644
index 000000000000..850076937d8d
--- /dev/null
+++ b/drivers/usb/gadget/imx_udc.h
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2005 Mike Lee(eemike@gmail.com)
+ *
+ * This udc driver is now under testing and code is based on pxa2xx_udc.h
+ * Please use it with your own risk!
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_USB_GADGET_IMX_H
+#define __LINUX_USB_GADGET_IMX_H
+
+#include <linux/types.h>
+
+/* Helper macros */
+#define EP_NO(ep) ((ep->bEndpointAddress) & ~USB_DIR_IN) /* IN:1, OUT:0 */
+#define EP_DIR(ep) ((ep->bEndpointAddress) & USB_DIR_IN ? 1 : 0)
+#define irq_to_ep(irq) (((irq) >= USBD_INT0) || ((irq) <= USBD_INT6) ? ((irq) - USBD_INT0) : (USBD_INT6)) /*should not happen*/
+#define ep_to_irq(ep) (EP_NO((ep)) + USBD_INT0)
+#define IMX_USB_NB_EP 6
+
+/* Driver structures */
+struct imx_request {
+ struct usb_request req;
+ struct list_head queue;
+ unsigned int in_use;
+};
+
+enum ep0_state {
+ EP0_IDLE,
+ EP0_IN_DATA_PHASE,
+ EP0_OUT_DATA_PHASE,
+ EP0_CONFIG,
+ EP0_STALL,
+};
+
+struct imx_ep_struct {
+ struct usb_ep ep;
+ struct imx_udc_struct *imx_usb;
+ struct list_head queue;
+ unsigned char stopped;
+ unsigned char fifosize;
+ unsigned char bEndpointAddress;
+ unsigned char bmAttributes;
+};
+
+struct imx_udc_struct {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct device *dev;
+ struct imx_ep_struct imx_ep[IMX_USB_NB_EP];
+ struct clk *clk;
+ enum ep0_state ep0state;
+ struct resource *res;
+ void __iomem *base;
+ unsigned char set_config;
+ int cfg,
+ intf,
+ alt,
+ usbd_int[7];
+};
+
+/* USB registers */
+#define USB_FRAME (0x00) /* USB frame */
+#define USB_SPEC (0x04) /* USB Spec */
+#define USB_STAT (0x08) /* USB Status */
+#define USB_CTRL (0x0C) /* USB Control */
+#define USB_DADR (0x10) /* USB Desc RAM addr */
+#define USB_DDAT (0x14) /* USB Desc RAM/EP buffer data */
+#define USB_INTR (0x18) /* USB interrupt */
+#define USB_MASK (0x1C) /* USB Mask */
+#define USB_ENAB (0x24) /* USB Enable */
+#define USB_EP_STAT(x) (0x30 + (x*0x30)) /* USB status/control */
+#define USB_EP_INTR(x) (0x34 + (x*0x30)) /* USB interrupt */
+#define USB_EP_MASK(x) (0x38 + (x*0x30)) /* USB mask */
+#define USB_EP_FDAT(x) (0x3C + (x*0x30)) /* USB FIFO data */
+#define USB_EP_FDAT0(x) (0x3C + (x*0x30)) /* USB FIFO data */
+#define USB_EP_FDAT1(x) (0x3D + (x*0x30)) /* USB FIFO data */
+#define USB_EP_FDAT2(x) (0x3E + (x*0x30)) /* USB FIFO data */
+#define USB_EP_FDAT3(x) (0x3F + (x*0x30)) /* USB FIFO data */
+#define USB_EP_FSTAT(x) (0x40 + (x*0x30)) /* USB FIFO status */
+#define USB_EP_FCTRL(x) (0x44 + (x*0x30)) /* USB FIFO control */
+#define USB_EP_LRFP(x) (0x48 + (x*0x30)) /* USB last read frame pointer */
+#define USB_EP_LWFP(x) (0x4C + (x*0x30)) /* USB last write frame pointer */
+#define USB_EP_FALRM(x) (0x50 + (x*0x30)) /* USB FIFO alarm */
+#define USB_EP_FRDP(x) (0x54 + (x*0x30)) /* USB FIFO read pointer */
+#define USB_EP_FWRP(x) (0x58 + (x*0x30)) /* USB FIFO write pointer */
+/* USB Control Register Bit Fields.*/
+#define CTRL_CMDOVER (1<<6) /* UDC status */
+#define CTRL_CMDERROR (1<<5) /* UDC status */
+#define CTRL_FE_ENA (1<<3) /* Enable Font End logic */
+#define CTRL_UDC_RST (1<<2) /* UDC reset */
+#define CTRL_AFE_ENA (1<<1) /* Analog Font end enable */
+#define CTRL_RESUME (1<<0) /* UDC resume */
+/* USB Status Register Bit Fields.*/
+#define STAT_RST (1<<8)
+#define STAT_SUSP (1<<7)
+#define STAT_CFG (3<<5)
+#define STAT_INTF (3<<3)
+#define STAT_ALTSET (7<<0)
+/* USB Interrupt Status/Mask Registers Bit fields */
+#define INTR_WAKEUP (1<<31) /* Wake up Interrupt */
+#define INTR_MSOF (1<<7) /* Missed Start of Frame */
+#define INTR_SOF (1<<6) /* Start of Frame */
+#define INTR_RESET_STOP (1<<5) /* Reset Signaling stop */
+#define INTR_RESET_START (1<<4) /* Reset Signaling start */
+#define INTR_RESUME (1<<3) /* Suspend to resume */
+#define INTR_SUSPEND (1<<2) /* Active to suspend */
+#define INTR_FRAME_MATCH (1<<1) /* Frame matched */
+#define INTR_CFG_CHG (1<<0) /* Configuration change occurred */
+/* USB Enable Register Bit Fields.*/
+#define ENAB_RST (1<<31) /* Reset USB modules */
+#define ENAB_ENAB (1<<30) /* Enable USB modules*/
+#define ENAB_SUSPEND (1<<29) /* Suspend USB modules */
+#define ENAB_ENDIAN (1<<28) /* Endian of USB modules */
+#define ENAB_PWRMD (1<<0) /* Power mode of USB modules */
+/* USB Descriptor Ram Address Register bit fields */
+#define DADR_CFG (1<<31) /* Configuration */
+#define DADR_BSY (1<<30) /* Busy status */
+#define DADR_DADR (0x1FF) /* Descriptor Ram Address */
+/* USB Descriptor RAM/Endpoint Buffer Data Register bit fields */
+#define DDAT_DDAT (0xFF) /* Descriptor Endpoint Buffer */
+/* USB Endpoint Status Register bit fields */
+#define EPSTAT_BCOUNT (0x7F<<16) /* Endpoint FIFO byte count */
+#define EPSTAT_SIP (1<<8) /* Endpoint setup in progress */
+#define EPSTAT_DIR (1<<7) /* Endpoint transfer direction */
+#define EPSTAT_MAX (3<<5) /* Endpoint Max packet size */
+#define EPSTAT_TYP (3<<3) /* Endpoint type */
+#define EPSTAT_ZLPS (1<<2) /* Send zero length packet */
+#define EPSTAT_FLUSH (1<<1) /* Endpoint FIFO Flush */
+#define EPSTAT_STALL (1<<0) /* Force stall */
+/* USB Endpoint FIFO Status Register bit fields */
+#define FSTAT_FRAME_STAT (0xF<<24) /* Frame status bit [0-3] */
+#define FSTAT_ERR (1<<22) /* FIFO error */
+#define FSTAT_UF (1<<21) /* FIFO underflow */
+#define FSTAT_OF (1<<20) /* FIFO overflow */
+#define FSTAT_FR (1<<19) /* FIFO frame ready */
+#define FSTAT_FULL (1<<18) /* FIFO full */
+#define FSTAT_ALRM (1<<17) /* FIFO alarm */
+#define FSTAT_EMPTY (1<<16) /* FIFO empty */
+/* USB Endpoint FIFO Control Register bit fields */
+#define FCTRL_WFR (1<<29) /* Write frame end */
+/* USB Endpoint Interrupt Status Regsiter bit fields */
+#define EPINTR_FIFO_FULL (1<<8) /* fifo full */
+#define EPINTR_FIFO_EMPTY (1<<7) /* fifo empty */
+#define EPINTR_FIFO_ERROR (1<<6) /* fifo error */
+#define EPINTR_FIFO_HIGH (1<<5) /* fifo high */
+#define EPINTR_FIFO_LOW (1<<4) /* fifo low */
+#define EPINTR_MDEVREQ (1<<3) /* multi Device request */
+#define EPINTR_EOT (1<<2) /* fifo end of transfer */
+#define EPINTR_DEVREQ (1<<1) /* Device request */
+#define EPINTR_EOF (1<<0) /* fifo end of frame */
+
+/* Debug macros */
+#ifdef DEBUG
+
+/* #define DEBUG_REQ */
+/* #define DEBUG_TRX */
+/* #define DEBUG_INIT */
+/* #define DEBUG_EP0 */
+/* #define DEBUG_EPX */
+/* #define DEBUG_IRQ */
+/* #define DEBUG_EPIRQ */
+/* #define DEBUG_DUMP */
+#define DEBUG_ERR
+
+#ifdef DEBUG_REQ
+ #define D_REQ(dev, args...) dev_dbg(dev, ## args)
+#else
+ #define D_REQ(dev, args...) do {} while (0)
+#endif /* DEBUG_REQ */
+
+#ifdef DEBUG_TRX
+ #define D_TRX(dev, args...) dev_dbg(dev, ## args)
+#else
+ #define D_TRX(dev, args...) do {} while (0)
+#endif /* DEBUG_TRX */
+
+#ifdef DEBUG_INIT
+ #define D_INI(dev, args...) dev_dbg(dev, ## args)
+#else
+ #define D_INI(dev, args...) do {} while (0)
+#endif /* DEBUG_INIT */
+
+#ifdef DEBUG_EP0
+ static const char *state_name[] = {
+ "EP0_IDLE",
+ "EP0_IN_DATA_PHASE",
+ "EP0_OUT_DATA_PHASE",
+ "EP0_CONFIG",
+ "EP0_STALL"
+ };
+ #define D_EP0(dev, args...) dev_dbg(dev, ## args)
+#else
+ #define D_EP0(dev, args...) do {} while (0)
+#endif /* DEBUG_EP0 */
+
+#ifdef DEBUG_EPX
+ #define D_EPX(dev, args...) dev_dbg(dev, ## args)
+#else
+ #define D_EPX(dev, args...) do {} while (0)
+#endif /* DEBUG_EP0 */
+
+#ifdef DEBUG_IRQ
+ static void dump_intr(const char *label, int irqreg, struct device *dev)
+ {
+ dev_dbg(dev, "<%s> USB_INTR=[%s%s%s%s%s%s%s%s%s]\n", label,
+ (irqreg & INTR_WAKEUP) ? " wake" : "",
+ (irqreg & INTR_MSOF) ? " msof" : "",
+ (irqreg & INTR_SOF) ? " sof" : "",
+ (irqreg & INTR_RESUME) ? " resume" : "",
+ (irqreg & INTR_SUSPEND) ? " suspend" : "",
+ (irqreg & INTR_RESET_STOP) ? " noreset" : "",
+ (irqreg & INTR_RESET_START) ? " reset" : "",
+ (irqreg & INTR_FRAME_MATCH) ? " fmatch" : "",
+ (irqreg & INTR_CFG_CHG) ? " config" : "");
+ }
+#else
+ #define dump_intr(x, y, z) do {} while (0)
+#endif /* DEBUG_IRQ */
+
+#ifdef DEBUG_EPIRQ
+ static void dump_ep_intr(const char *label, int nr, int irqreg, struct device *dev)
+ {
+ dev_dbg(dev, "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, nr,
+ (irqreg & EPINTR_FIFO_FULL) ? " full" : "",
+ (irqreg & EPINTR_FIFO_EMPTY) ? " fempty" : "",
+ (irqreg & EPINTR_FIFO_ERROR) ? " ferr" : "",
+ (irqreg & EPINTR_FIFO_HIGH) ? " fhigh" : "",
+ (irqreg & EPINTR_FIFO_LOW) ? " flow" : "",
+ (irqreg & EPINTR_MDEVREQ) ? " mreq" : "",
+ (irqreg & EPINTR_EOF) ? " eof" : "",
+ (irqreg & EPINTR_DEVREQ) ? " devreq" : "",
+ (irqreg & EPINTR_EOT) ? " eot" : "");
+ }
+#else
+ #define dump_ep_intr(x, y, z, i) do {} while (0)
+#endif /* DEBUG_IRQ */
+
+#ifdef DEBUG_DUMP
+ static void dump_usb_stat(const char *label, struct imx_udc_struct *imx_usb)
+ {
+ int temp = __raw_readl(imx_usb->base + USB_STAT);
+
+ dev_dbg(imx_usb->dev,
+ "<%s> USB_STAT=[%s%s CFG=%d, INTF=%d, ALTR=%d]\n", label,
+ (temp & STAT_RST) ? " reset" : "",
+ (temp & STAT_SUSP) ? " suspend" : "",
+ (temp & STAT_CFG) >> 5,
+ (temp & STAT_INTF) >> 3,
+ (temp & STAT_ALTSET));
+ }
+
+ static void dump_ep_stat(const char *label, struct imx_ep_struct *imx_ep)
+ {
+ int temp = __raw_readl(imx_ep->imx_usb->base + USB_EP_INTR(EP_NO(imx_ep)));
+
+ dev_dbg(imx_ep->imx_usb->dev,
+ "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, EP_NO(imx_ep),
+ (temp & EPINTR_FIFO_FULL) ? " full" : "",
+ (temp & EPINTR_FIFO_EMPTY) ? " fempty" : "",
+ (temp & EPINTR_FIFO_ERROR) ? " ferr" : "",
+ (temp & EPINTR_FIFO_HIGH) ? " fhigh" : "",
+ (temp & EPINTR_FIFO_LOW) ? " flow" : "",
+ (temp & EPINTR_MDEVREQ) ? " mreq" : "",
+ (temp & EPINTR_EOF) ? " eof" : "",
+ (temp & EPINTR_DEVREQ) ? " devreq" : "",
+ (temp & EPINTR_EOT) ? " eot" : "");
+
+ temp = __raw_readl(imx_ep->imx_usb->base + USB_EP_STAT(EP_NO(imx_ep)));
+
+ dev_dbg(imx_ep->imx_usb->dev,
+ "<%s> EP%d_STAT=[%s%s bcount=%d]\n", label, EP_NO(imx_ep),
+ (temp & EPSTAT_SIP) ? " sip" : "",
+ (temp & EPSTAT_STALL) ? " stall" : "",
+ (temp & EPSTAT_BCOUNT) >> 16);
+
+ temp = __raw_readl(imx_ep->imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep)));
+
+ dev_dbg(imx_ep->imx_usb->dev,
+ "<%s> EP%d_FSTAT=[%s%s%s%s%s%s%s]\n", label, EP_NO(imx_ep),
+ (temp & FSTAT_ERR) ? " ferr" : "",
+ (temp & FSTAT_UF) ? " funder" : "",
+ (temp & FSTAT_OF) ? " fover" : "",
+ (temp & FSTAT_FR) ? " fready" : "",
+ (temp & FSTAT_FULL) ? " ffull" : "",
+ (temp & FSTAT_ALRM) ? " falarm" : "",
+ (temp & FSTAT_EMPTY) ? " fempty" : "");
+ }
+
+ static void dump_req(const char *label, struct imx_ep_struct *imx_ep, struct usb_request *req)
+ {
+ int i;
+
+ if (!req || !req->buf) {
+ dev_dbg(imx_ep->imx_usb->dev, "<%s> req or req buf is free\n", label);
+ return;
+ }
+
+ if ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state == EP0_IN_DATA_PHASE)
+ || (EP_NO(imx_ep) && EP_DIR(imx_ep))) {
+
+ dev_dbg(imx_ep->imx_usb->dev, "<%s> request dump <", label);
+ for (i = 0; i < req->length; i++)
+ printk("%02x-", *((u8 *)req->buf + i));
+ printk(">\n");
+ }
+ }
+
+#else
+ #define dump_ep_stat(x, y) do {} while (0)
+ #define dump_usb_stat(x, y) do {} while (0)
+ #define dump_req(x, y, z) do {} while (0)
+#endif /* DEBUG_DUMP */
+
+#ifdef DEBUG_ERR
+ #define D_ERR(dev, args...) dev_dbg(dev, ## args)
+#else
+ #define D_ERR(dev, args...) do {} while (0)
+#endif
+
+#else
+ #define D_REQ(dev, args...) do {} while (0)
+ #define D_TRX(dev, args...) do {} while (0)
+ #define D_INI(dev, args...) do {} while (0)
+ #define D_EP0(dev, args...) do {} while (0)
+ #define D_EPX(dev, args...) do {} while (0)
+ #define dump_ep_intr(x, y, z, i) do {} while (0)
+ #define dump_intr(x, y, z) do {} while (0)
+ #define dump_ep_stat(x, y) do {} while (0)
+ #define dump_usb_stat(x, y) do {} while (0)
+ #define dump_req(x, y, z) do {} while (0)
+ #define D_ERR(dev, args...) do {} while (0)
+#endif /* DEBUG */
+
+#endif /* __LINUX_USB_GADGET_IMX_H */
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 3a8879ec2061..43dcf9e1af6b 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -1546,8 +1546,6 @@ static void nop_completion(struct usb_ep *ep, struct usb_request *r)
{
}
-#define resource_len(r) (((r)->end - (r)->start) + 1)
-
static int __init m66592_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -1560,11 +1558,10 @@ static int __init m66592_probe(struct platform_device *pdev)
int ret = 0;
int i;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- (char *)udc_name);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
- pr_err("platform_get_resource_byname error.\n");
+ pr_err("platform_get_resource error.\n");
goto clean_up;
}
@@ -1575,7 +1572,7 @@ static int __init m66592_probe(struct platform_device *pdev)
goto clean_up;
}
- reg = ioremap(res->start, resource_len(res));
+ reg = ioremap(res->start, resource_size(res));
if (reg == NULL) {
ret = -ENOMEM;
pr_err("ioremap error.\n");
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 8ae70de2c37d..12c6d83b218c 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -669,7 +669,7 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
/* 2280 may be polling VALID_BIT through ep->dma->dmadesc */
wmb ();
- td->dmacount = cpu_to_le32p (&dmacount);
+ td->dmacount = cpu_to_le32(dmacount);
}
static const u32 dmactl_default =
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 34e9e393f929..57d9641c6bf8 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -3006,7 +3006,7 @@ cleanup1:
cleanup0:
if (xceiv)
- put_device(xceiv->dev);
+ otg_put_transceiver(xceiv);
if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
clk_disable(hhc_clk);
@@ -3034,7 +3034,7 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
pullup_disable(udc);
if (udc->transceiver) {
- put_device(udc->transceiver->dev);
+ otg_put_transceiver(udc->transceiver);
udc->transceiver = NULL;
}
omap_writew(0, UDC_SYSCON1);
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index 697a0ca349bf..9b36205c5759 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -2198,7 +2198,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
udc_disable(dev);
udc_reinit(dev);
- dev->vbus = is_vbus_present();
+ dev->vbus = !!is_vbus_present();
/* irq setup after old hardware state is cleaned up */
retval = request_irq(irq, pxa25x_udc_irq,
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 65110d02a206..990f40f988d4 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -430,7 +430,6 @@ static void pio_irq_enable(struct pxa_ep *ep)
/**
* pio_irq_disable - Disables irq generation for one endpoint
* @ep: udc endpoint
- * @index: endpoint number
*/
static void pio_irq_disable(struct pxa_ep *ep)
{
@@ -586,7 +585,6 @@ static void inc_ep_stats_reqs(struct pxa_ep *ep, int is_in)
* inc_ep_stats_bytes - Update ep stats counts
* @ep: physical endpoint
* @count: bytes transfered on endpoint
- * @req: usb request
* @is_in: ep direction (USB_DIR_IN or 0)
*/
static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in)
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index c7e255636803..9a2b8920532d 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -36,6 +36,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/gpio.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
@@ -51,7 +52,6 @@
#include <mach/irqs.h>
#include <mach/hardware.h>
-#include <mach/regs-gpio.h>
#include <plat/regs-udc.h>
#include <plat/udc.h>
@@ -1510,11 +1510,7 @@ static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev)
dprintk(DEBUG_NORMAL, "%s()\n", __func__);
- /* some cpus cannot read from an line configured to IRQ! */
- s3c2410_gpio_cfgpin(udc_info->vbus_pin, S3C2410_GPIO_INPUT);
- value = s3c2410_gpio_getpin(udc_info->vbus_pin);
- s3c2410_gpio_cfgpin(udc_info->vbus_pin, S3C2410_GPIO_SFN2);
-
+ value = gpio_get_value(udc_info->vbus_pin) ? 1 : 0;
if (udc_info->vbus_pin_inverted)
value = !value;
@@ -1802,7 +1798,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
struct s3c2410_udc *udc = &memory;
struct device *dev = &pdev->dev;
int retval;
- unsigned int irq;
+ int irq;
dev_dbg(dev, "%s()\n", __func__);
@@ -1861,7 +1857,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
/* irq setup after old hardware state is cleaned up */
retval = request_irq(IRQ_USBD, s3c2410_udc_irq,
- IRQF_DISABLED, gadget_name, udc);
+ IRQF_DISABLED, gadget_name, udc);
if (retval != 0) {
dev_err(dev, "cannot get irq %i, err %d\n", IRQ_USBD, retval);
@@ -1872,17 +1868,28 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
dev_dbg(dev, "got irq %i\n", IRQ_USBD);
if (udc_info && udc_info->vbus_pin > 0) {
- irq = s3c2410_gpio_getirq(udc_info->vbus_pin);
+ retval = gpio_request(udc_info->vbus_pin, "udc vbus");
+ if (retval < 0) {
+ dev_err(dev, "cannot claim vbus pin\n");
+ goto err_int;
+ }
+
+ irq = gpio_to_irq(udc_info->vbus_pin);
+ if (irq < 0) {
+ dev_err(dev, "no irq for gpio vbus pin\n");
+ goto err_gpio_claim;
+ }
+
retval = request_irq(irq, s3c2410_udc_vbus_irq,
IRQF_DISABLED | IRQF_TRIGGER_RISING
| IRQF_TRIGGER_FALLING | IRQF_SHARED,
gadget_name, udc);
if (retval != 0) {
- dev_err(dev, "can't get vbus irq %i, err %d\n",
+ dev_err(dev, "can't get vbus irq %d, err %d\n",
irq, retval);
retval = -EBUSY;
- goto err_int;
+ goto err_gpio_claim;
}
dev_dbg(dev, "got irq %i\n", irq);
@@ -1902,6 +1909,9 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
return 0;
+err_gpio_claim:
+ if (udc_info && udc_info->vbus_pin > 0)
+ gpio_free(udc_info->vbus_pin);
err_int:
free_irq(IRQ_USBD, udc);
err_map:
@@ -1927,7 +1937,7 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
debugfs_remove(udc->regs_info);
if (udc_info && udc_info->vbus_pin > 0) {
- irq = s3c2410_gpio_getirq(udc_info->vbus_pin);
+ irq = gpio_to_irq(udc_info->vbus_pin);
free_irq(irq, udc);
}
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index d9739d52f8f5..96d65ca06ecd 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -716,6 +716,14 @@ static int __init get_ether_addr(const char *str, u8 *dev_addr)
static struct eth_dev *the_dev;
+static const struct net_device_ops eth_netdev_ops = {
+ .ndo_open = eth_open,
+ .ndo_stop = eth_stop,
+ .ndo_start_xmit = eth_start_xmit,
+ .ndo_change_mtu = ueth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
/**
* gether_setup - initialize one ethernet-over-usb link
@@ -764,12 +772,8 @@ int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
if (ethaddr)
memcpy(ethaddr, dev->host_mac, ETH_ALEN);
- net->change_mtu = ueth_change_mtu;
- net->hard_start_xmit = eth_start_xmit;
- net->open = eth_open;
- net->stop = eth_stop;
- /* watchdog_timeo, tx_timeout ... */
- /* set_multicast_list */
+ net->netdev_ops = &eth_netdev_ops;
+
SET_ETHTOOL_OPS(net, &ops);
/* two kinds of host-initiated state changes:
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index f3a75a929e0a..2b476b6b3d4d 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -96,6 +96,19 @@ config USB_EHCI_HCD_PPC_OF
Enables support for the USB controller present on the PowerPC
OpenFirmware platform bus.
+config USB_OXU210HP_HCD
+ tristate "OXU210HP HCD support"
+ depends on USB
+ ---help---
+ The OXU210HP is an USB host/OTG/device controller. Enable this
+ option if your board has this chip. If unsure, say N.
+
+ This driver does not support isochronous transfers and doesn't
+ implement OTG nor USB device controllers.
+
+ To compile this driver as a module, choose M here: the
+ module will be called oxu210hp-hcd.
+
config USB_ISP116X_HCD
tristate "ISP116X HCD support"
depends on USB
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 23be22224044..e5f3f20787e4 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_USB_WHCI_HCD) += whci/
obj-$(CONFIG_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
+obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o
obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 0cb53ca8d343..7f4ace73d44a 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -455,9 +455,7 @@ static void qh_lines (
(scratch >> 16) & 0x7fff,
scratch,
td->urb);
- if (temp < 0)
- temp = 0;
- else if (size < temp)
+ if (size < temp)
temp = size;
size -= temp;
next += temp;
@@ -466,9 +464,7 @@ static void qh_lines (
}
temp = snprintf (next, size, "\n");
- if (temp < 0)
- temp = 0;
- else if (size < temp)
+ if (size < temp)
temp = size;
size -= temp;
next += temp;
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 218f9660d7ee..97a53a48a3d8 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -194,6 +194,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
u32 temp;
u32 power_okay;
int i;
+ u8 resume_needed = 0;
if (time_before (jiffies, ehci->next_statechange))
msleep(5);
@@ -228,7 +229,9 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
/* Some controller/firmware combinations need a delay during which
* they set up the port statuses. See Bugzilla #8190. */
- mdelay(8);
+ spin_unlock_irq(&ehci->lock);
+ msleep(8);
+ spin_lock_irq(&ehci->lock);
/* manually resume the ports we suspended during bus_suspend() */
i = HCS_N_PORTS (ehci->hcs_params);
@@ -236,12 +239,21 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
if (test_bit(i, &ehci->bus_suspended) &&
- (temp & PORT_SUSPEND))
+ (temp & PORT_SUSPEND)) {
temp |= PORT_RESUME;
+ resume_needed = 1;
+ }
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
}
+
+ /* msleep for 20ms only if code is trying to resume port */
+ if (resume_needed) {
+ spin_unlock_irq(&ehci->lock);
+ msleep(20);
+ spin_lock_irq(&ehci->lock);
+ }
+
i = HCS_N_PORTS (ehci->hcs_params);
- mdelay (20);
while (i--) {
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
if (test_bit(i, &ehci->bus_suspended) &&
@@ -422,8 +434,15 @@ static int check_reset_complete (
port_status &= ~PORT_RWC_BITS;
ehci_writel(ehci, port_status, status_reg);
- } else
+ /* ensure 440EPX ohci controller state is operational */
+ if (ehci->has_amcc_usb23)
+ set_ohci_hcfs(ehci, 1);
+ } else {
ehci_dbg (ehci, "port %d high speed\n", index + 1);
+ /* ensure 440EPx ohci controller state is suspended */
+ if (ehci->has_amcc_usb23)
+ set_ohci_hcfs(ehci, 0);
+ }
return port_status;
}
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 36864f958444..bdc6e86e1f8b 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -219,15 +219,19 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
/* Serial Bus Release Number is at PCI 0x60 offset */
pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
- /* Workaround current PCI init glitch: wakeup bits aren't
- * being set from PCI PM capability.
+ /* Keep this around for a while just in case some EHCI
+ * implementation uses legacy PCI PM support. This test
+ * can be removed on 17 Dec 2009 if the dev_warn() hasn't
+ * been triggered by then.
*/
if (!device_can_wakeup(&pdev->dev)) {
u16 port_wake;
pci_read_config_word(pdev, 0x62, &port_wake);
- if (port_wake & 0x0001)
+ if (port_wake & 0x0001) {
+ dev_warn(&pdev->dev, "Enabling legacy PCI PM\n");
device_init_wakeup(&pdev->dev, 1);
+ }
}
#ifdef CONFIG_USB_SUSPEND
@@ -428,6 +432,8 @@ static struct pci_driver ehci_pci_driver = {
#ifdef CONFIG_PM
.suspend = usb_hcd_pci_suspend,
+ .suspend_late = usb_hcd_pci_suspend_late,
+ .resume_early = usb_hcd_pci_resume_early,
.resume = usb_hcd_pci_resume,
#endif
.shutdown = usb_hcd_pci_shutdown,
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index b018deed2e8f..ef732b704f53 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -107,11 +107,13 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dn = op->node;
struct usb_hcd *hcd;
- struct ehci_hcd *ehci;
+ struct ehci_hcd *ehci = NULL;
struct resource res;
int irq;
int rv;
+ struct device_node *np;
+
if (usb_disabled())
return -ENODEV;
@@ -149,6 +151,20 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
}
ehci = hcd_to_ehci(hcd);
+ np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
+ if (np != NULL) {
+ /* claim we really affected by usb23 erratum */
+ if (!of_address_to_resource(np, 0, &res))
+ ehci->ohci_hcctrl_reg = ioremap(res.start +
+ OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN);
+ else
+ pr_debug(__FILE__ ": no ohci offset in fdt\n");
+ if (!ehci->ohci_hcctrl_reg) {
+ pr_debug(__FILE__ ": ioremap for ohci hcctrl failed\n");
+ } else {
+ ehci->has_amcc_usb23 = 1;
+ }
+ }
if (of_get_property(dn, "big-endian", NULL)) {
ehci->big_endian_mmio = 1;
@@ -181,6 +197,9 @@ err_ioremap:
irq_dispose_mapping(irq);
err_irq:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+ if (ehci->has_amcc_usb23)
+ iounmap(ehci->ohci_hcctrl_reg);
err_rmr:
usb_put_hcd(hcd);
@@ -191,6 +210,11 @@ err_rmr:
static int ehci_hcd_ppc_of_remove(struct of_device *op)
{
struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ struct device_node *np;
+ struct resource res;
+
dev_set_drvdata(&op->dev, NULL);
dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
@@ -201,6 +225,25 @@ static int ehci_hcd_ppc_of_remove(struct of_device *op)
irq_dispose_mapping(hcd->irq);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ /* use request_mem_region to test if the ohci driver is loaded. if so
+ * ensure the ohci core is operational.
+ */
+ if (ehci->has_amcc_usb23) {
+ np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
+ if (np != NULL) {
+ if (!of_address_to_resource(np, 0, &res))
+ if (!request_mem_region(res.start,
+ 0x4, hcd_name))
+ set_ohci_hcfs(ehci, 1);
+ else
+ release_mem_region(res.start, 0x4);
+ else
+ pr_debug(__FILE__ ": no ohci offset in fdt\n");
+ of_node_put(np);
+ }
+
+ iounmap(ehci->ohci_hcctrl_reg);
+ }
usb_put_hcd(hcd);
return 0;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index c7d4b5a06bdb..fb7054ccf4fc 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -120,6 +120,16 @@ struct ehci_hcd { /* one per controller */
unsigned has_fsl_port_bug:1; /* FreeScale */
unsigned big_endian_mmio:1;
unsigned big_endian_desc:1;
+ unsigned has_amcc_usb23:1;
+
+ /* required for usb32 quirk */
+ #define OHCI_CTRL_HCFS (3 << 6)
+ #define OHCI_USB_OPER (2 << 6)
+ #define OHCI_USB_SUSPEND (3 << 6)
+
+ #define OHCI_HCCTRL_OFFSET 0x4
+ #define OHCI_HCCTRL_LEN 0x4
+ __hc32 *ohci_hcctrl_reg;
u8 sbrn; /* packed release number */
@@ -636,6 +646,30 @@ static inline void ehci_writel(const struct ehci_hcd *ehci,
#endif
}
+/*
+ * On certain ppc-44x SoC there is a HW issue, that could only worked around with
+ * explicit suspend/operate of OHCI. This function hereby makes sense only on that arch.
+ * Other common bits are dependant on has_amcc_usb23 quirk flag.
+ */
+#ifdef CONFIG_44x
+static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
+{
+ u32 hc_control;
+
+ hc_control = (readl_be(ehci->ohci_hcctrl_reg) & ~OHCI_CTRL_HCFS);
+ if (operational)
+ hc_control |= OHCI_USB_OPER;
+ else
+ hc_control |= OHCI_USB_SUSPEND;
+
+ writel_be(hc_control, ehci->ohci_hcctrl_reg);
+ (void) readl_be(ehci->ohci_hcctrl_reg);
+}
+#else
+static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
+{ }
+#endif
+
/*-------------------------------------------------------------------------*/
/*
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index 8017f1cf78e2..b899f1a59c26 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -435,14 +435,13 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
/*
* PORT 1 Control register of the ISP1760 is the OTG control
- * register on ISP1761.
+ * register on ISP1761. Since there is no OTG or device controller
+ * support in this driver, we use port 1 as a "normal" USB host port on
+ * both chips.
*/
- if (!(priv->devflags & ISP1760_FLAG_ISP1761) &&
- !(priv->devflags & ISP1760_FLAG_PORT1_DIS)) {
- isp1760_writel(PORT1_POWER | PORT1_INIT2,
- hcd->regs + HC_PORT1_CTRL);
- mdelay(10);
- }
+ isp1760_writel(PORT1_POWER | PORT1_INIT2,
+ hcd->regs + HC_PORT1_CTRL);
+ mdelay(10);
priv->hcs_params = isp1760_readl(hcd->regs + HC_HCSPARAMS);
diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h
index 4377277667d9..a9daea587962 100644
--- a/drivers/usb/host/isp1760-hcd.h
+++ b/drivers/usb/host/isp1760-hcd.h
@@ -135,7 +135,6 @@ typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
* indicate the most "atypical" case, so that a devflags of 0 is
* a sane default configuration.
*/
-#define ISP1760_FLAG_PORT1_DIS 0x00000001 /* Port 1 disabled */
#define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */
#define ISP1760_FLAG_OTG_EN 0x00000004 /* Port 1 supports OTG */
#define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index b87ca7cf4b37..4cf7ca428b33 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -60,9 +60,6 @@ static int of_isp1760_probe(struct of_device *dev,
if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
devflags |= ISP1760_FLAG_ISP1761;
- if (of_get_property(dp, "port1-disable", NULL) != NULL)
- devflags |= ISP1760_FLAG_PORT1_DIS;
-
/* Some systems wire up only 16 of the 32 data lines */
prop = of_get_property(dp, "bus-width", NULL);
if (prop && *prop == 16)
@@ -129,23 +126,23 @@ static struct of_platform_driver isp1760_of_driver = {
#endif
#ifdef CONFIG_PCI
-static u32 nxp_pci_io_base;
-static u32 iolength;
-static u32 pci_mem_phy0;
-static u32 length;
-static u8 __iomem *chip_addr;
-static u8 __iomem *iobase;
-
static int __devinit isp1761_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
u8 latency, limit;
__u32 reg_data;
int retry_count;
- int length;
- int status = 1;
struct usb_hcd *hcd;
unsigned int devflags = 0;
+ int ret_status = 0;
+
+ resource_size_t pci_mem_phy0;
+ resource_size_t memlength;
+
+ u8 __iomem *chip_addr;
+ u8 __iomem *iobase;
+ resource_size_t nxp_pci_io_base;
+ resource_size_t iolength;
if (usb_disabled())
return -ENODEV;
@@ -168,26 +165,30 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
iobase = ioremap_nocache(nxp_pci_io_base, iolength);
if (!iobase) {
printk(KERN_ERR "ioremap #1\n");
- release_mem_region(nxp_pci_io_base, iolength);
- return -ENOMEM;
+ ret_status = -ENOMEM;
+ goto cleanup1;
}
/* Grab the PLX PCI shared memory of the ISP 1761 we need */
pci_mem_phy0 = pci_resource_start(dev, 3);
- length = pci_resource_len(dev, 3);
-
- if (length < 0xffff) {
- printk(KERN_ERR "memory length for this resource is less than "
- "required\n");
- release_mem_region(nxp_pci_io_base, iolength);
- iounmap(iobase);
- return -ENOMEM;
+ memlength = pci_resource_len(dev, 3);
+ if (memlength < 0xffff) {
+ printk(KERN_ERR "memory length for this resource is wrong\n");
+ ret_status = -ENOMEM;
+ goto cleanup2;
}
- if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) {
+ if (!request_mem_region(pci_mem_phy0, memlength, "ISP-PCI")) {
printk(KERN_ERR "host controller already in use\n");
- release_mem_region(nxp_pci_io_base, iolength);
- iounmap(iobase);
- return -EBUSY;
+ ret_status = -EBUSY;
+ goto cleanup2;
+ }
+
+ /* map available memory */
+ chip_addr = ioremap_nocache(pci_mem_phy0,memlength);
+ if (!chip_addr) {
+ printk(KERN_ERR "Error ioremap failed\n");
+ ret_status = -ENOMEM;
+ goto cleanup3;
}
/* bad pci latencies can contribute to overruns */
@@ -210,39 +211,54 @@ static int __devinit isp1761_pci_probe(struct pci_dev *dev,
* */
writel(0xface, chip_addr + HC_SCRATCH_REG);
udelay(100);
- reg_data = readl(chip_addr + HC_SCRATCH_REG);
+ reg_data = readl(chip_addr + HC_SCRATCH_REG) & 0x0000ffff;
retry_count--;
}
+ iounmap(chip_addr);
+
/* Host Controller presence is detected by writing to scratch register
* and reading back and checking the contents are same or not
*/
if (reg_data != 0xFACE) {
dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
- goto clean;
+ ret_status = -ENOMEM;
+ goto cleanup3;
}
pci_set_master(dev);
- status = readl(iobase + 0x68);
- status |= 0x900;
- writel(status, iobase + 0x68);
+ /* configure PLX PCI chip to pass interrupts */
+#define PLX_INT_CSR_REG 0x68
+ reg_data = readl(iobase + PLX_INT_CSR_REG);
+ reg_data |= 0x900;
+ writel(reg_data, iobase + PLX_INT_CSR_REG);
dev->dev.dma_mask = NULL;
- hcd = isp1760_register(pci_mem_phy0, length, dev->irq,
+ hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq,
IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev_name(&dev->dev),
devflags);
- if (!IS_ERR(hcd)) {
- pci_set_drvdata(dev, hcd);
- return 0;
+ if (IS_ERR(hcd)) {
+ ret_status = -ENODEV;
+ goto cleanup3;
}
-clean:
- status = -ENODEV;
+
+ /* done with PLX IO access */
+ iounmap(iobase);
+ release_mem_region(nxp_pci_io_base, iolength);
+
+ pci_set_drvdata(dev, hcd);
+ return 0;
+
+cleanup3:
+ release_mem_region(pci_mem_phy0, memlength);
+cleanup2:
iounmap(iobase);
- release_mem_region(pci_mem_phy0, length);
+cleanup1:
release_mem_region(nxp_pci_io_base, iolength);
- return status;
+ return ret_status;
}
+
static void isp1761_pci_remove(struct pci_dev *dev)
{
struct usb_hcd *hcd;
@@ -255,12 +271,6 @@ static void isp1761_pci_remove(struct pci_dev *dev)
usb_put_hcd(hcd);
pci_disable_device(dev);
-
- iounmap(iobase);
- iounmap(chip_addr);
-
- release_mem_region(nxp_pci_io_base, iolength);
- release_mem_region(pci_mem_phy0, length);
}
static void isp1761_pci_shutdown(struct pci_dev *dev)
@@ -268,12 +278,16 @@ static void isp1761_pci_shutdown(struct pci_dev *dev)
printk(KERN_ERR "ips1761_pci_shutdown\n");
}
-static const struct pci_device_id isp1760_plx [] = { {
- /* handle any USB 2.0 EHCI controller */
- PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)), ~0),
- .driver_data = 0,
-},
-{ /* end: all zeroes */ }
+static const struct pci_device_id isp1760_plx [] = {
+ {
+ .class = PCI_CLASS_BRIDGE_OTHER << 8,
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = 0x5406,
+ .subvendor = PCI_VENDOR_ID_PLX,
+ .subdevice = 0x9054,
+ },
+ { }
};
MODULE_DEVICE_TABLE(pci, isp1760_plx);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 8aa3f4556a32..65a9609f4ad6 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -589,13 +589,15 @@ static int ohci_run (struct ohci_hcd *ohci)
/* also: power/overcurrent flags in roothub.a */
}
- /* Reset USB nearly "by the book". RemoteWakeupConnected was
- * saved if boot firmware (BIOS/SMM/...) told us it's connected,
- * or if bus glue did the same (e.g. for PCI add-in cards with
- * PCI PM support).
+ /* Reset USB nearly "by the book". RemoteWakeupConnected has
+ * to be checked in case boot firmware (BIOS/SMM/...) has set up
+ * wakeup in a way the bus isn't aware of (e.g., legacy PCI PM).
+ * If the bus glue detected wakeup capability then it should
+ * already be enabled. Either way, if wakeup should be enabled
+ * but isn't, we'll enable it now.
*/
if ((ohci->hc_control & OHCI_CTRL_RWC) != 0
- && !device_may_wakeup(hcd->self.controller))
+ && !device_can_wakeup(hcd->self.controller))
device_init_wakeup(hcd->self.controller, 1);
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index a9c2ae36c7ad..8b28ae7865ba 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -355,9 +355,9 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd)
/* RWC may not be set for add-in PCI cards, since boot
* firmware probably ignored them. This transfers PCI
- * PM wakeup capabilities (once the PCI layer is fixed).
+ * PM wakeup capabilities.
*/
- if (device_may_wakeup(&pdev->dev))
+ if (device_can_wakeup(&pdev->dev))
ohci->hc_control |= OHCI_CTRL_RWC;
}
#endif /* CONFIG_PM */
@@ -487,6 +487,8 @@ static struct pci_driver ohci_pci_driver = {
#ifdef CONFIG_PM
.suspend = usb_hcd_pci_suspend,
+ .suspend_late = usb_hcd_pci_suspend_late,
+ .resume_early = usb_hcd_pci_resume_early,
.resume = usb_hcd_pci_resume,
#endif
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index e306ca6aef3d..100bf3d8437c 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -106,65 +106,34 @@ extern int ocpi_enable(void);
static struct clk *usb_clk;
-static int isp1301_probe(struct i2c_adapter *adap);
-static int isp1301_detach(struct i2c_client *client);
-
static const unsigned short normal_i2c[] =
{ ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, 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,
- .probe = dummy_i2c_addrlist,
- .ignore = dummy_i2c_addrlist,
-};
-
-struct i2c_driver isp1301_driver = {
- .driver = {
- .name = "isp1301_pnx",
- },
- .attach_adapter = isp1301_probe,
- .detach_client = isp1301_detach,
-};
-static int isp1301_attach(struct i2c_adapter *adap, int addr, int kind)
+static int isp1301_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- struct i2c_client *c;
- int err;
-
- c = kzalloc(sizeof(*c), GFP_KERNEL);
- if (!c)
- return -ENOMEM;
-
- strlcpy(c->name, "isp1301_pnx", I2C_NAME_SIZE);
- c->flags = 0;
- c->addr = addr;
- c->adapter = adap;
- c->driver = &isp1301_driver;
-
- err = i2c_attach_client(c);
- if (err) {
- kfree(c);
- return err;
- }
-
- isp1301_i2c_client = c;
-
return 0;
}
-static int isp1301_probe(struct i2c_adapter *adap)
+static int isp1301_remove(struct i2c_client *client)
{
- return i2c_probe(adap, &addr_data, isp1301_attach);
-}
-
-static int isp1301_detach(struct i2c_client *client)
-{
- i2c_detach_client(client);
- kfree(isp1301_i2c_client);
return 0;
}
+const struct i2c_device_id isp1301_id[] = {
+ { "isp1301_pnx", 0 },
+ { }
+};
+
+struct i2c_driver isp1301_driver = {
+ .driver = {
+ .name = "isp1301_pnx",
+ },
+ .probe = isp1301_probe,
+ .remove = isp1301_remove,
+ .id_table = isp1301_id,
+};
+
static void i2c_write(u8 buf, u8 subaddr)
{
char tmpbuf[2];
@@ -328,6 +297,8 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
struct usb_hcd *hcd = 0;
struct ohci_hcd *ohci;
const struct hc_driver *driver = &ohci_pnx4008_hc_driver;
+ struct i2c_adapter *i2c_adap;
+ struct i2c_board_info i2c_info;
int ret = 0, irq;
@@ -351,9 +322,20 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
ret = i2c_add_driver(&isp1301_driver);
if (ret < 0) {
- err("failed to connect I2C to ISP1301 USB Transceiver");
+ err("failed to add ISP1301 driver");
goto out;
}
+ i2c_adap = i2c_get_adapter(2);
+ memset(&i2c_info, 0, sizeof(struct i2c_board_info));
+ strlcpy(i2c_info.name, "isp1301_pnx", I2C_NAME_SIZE);
+ isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
+ normal_i2c);
+ i2c_put_adapter(i2c_adap);
+ if (!isp1301_i2c_client) {
+ err("failed to connect I2C to ISP1301 USB Transceiver");
+ ret = -ENODEV;
+ goto out_i2c_driver;
+ }
isp1301_configure();
@@ -429,6 +411,9 @@ out3:
out2:
clk_put(usb_clk);
out1:
+ i2c_unregister_client(isp1301_i2c_client);
+ isp1301_i2c_client = NULL;
+out_i2c_driver:
i2c_del_driver(&isp1301_driver);
out:
return ret;
@@ -445,6 +430,8 @@ static int usb_hcd_pnx4008_remove(struct platform_device *pdev)
pnx4008_unset_usb_bits();
clk_disable(usb_clk);
clk_put(usb_clk);
+ i2c_unregister_client(isp1301_i2c_client);
+ isp1301_i2c_client = NULL;
i2c_del_driver(&isp1301_driver);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 7ac53264ead3..68a301710297 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -91,6 +91,7 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
int rv;
int is_bigendian;
+ struct device_node *np;
if (usb_disabled())
return -ENODEV;
@@ -147,6 +148,30 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
if (rv == 0)
return 0;
+ /* by now, 440epx is known to show usb_23 erratum */
+ np = of_find_compatible_node(NULL, NULL, "ibm,usb-ehci-440epx");
+
+ /* Work around - At this point ohci_run has executed, the
+ * controller is running, everything, the root ports, etc., is
+ * set up. If the ehci driver is loaded, put the ohci core in
+ * the suspended state. The ehci driver will bring it out of
+ * suspended state when / if a non-high speed USB device is
+ * attached to the USB Host port. If the ehci driver is not
+ * loaded, do nothing. request_mem_region is used to test if
+ * the ehci driver is loaded.
+ */
+ if (np != NULL) {
+ if (!of_address_to_resource(np, 0, &res)) {
+ if (!request_mem_region(res.start, 0x4, hcd_name)) {
+ writel_be((readl_be(&ohci->regs->control) |
+ OHCI_USB_SUSPEND), &ohci->regs->control);
+ (void) readl_be(&ohci->regs->control);
+ } else
+ release_mem_region(res.start, 0x4);
+ } else
+ pr_debug(__FILE__ ": cannot get ehci offset from fdt\n");
+ }
+
iounmap(hcd->regs);
err_ioremap:
irq_dispose_mapping(irq);
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
index f9f134af0bd1..8dabe8e31d8c 100644
--- a/drivers/usb/host/ohci-tmio.c
+++ b/drivers/usb/host/ohci-tmio.c
@@ -201,7 +201,7 @@ static int __devinit ohci_hcd_tmio_drv_probe(struct platform_device *dev)
if (!cell)
return -EINVAL;
- hcd = usb_create_hcd(&ohci_tmio_hc_driver, &dev->dev, dev->dev.bus_id);
+ hcd = usb_create_hcd(&ohci_tmio_hc_driver, &dev->dev, dev_name(&dev->dev));
if (!hcd) {
ret = -ENOMEM;
goto err_usb_create_hcd;
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
new file mode 100644
index 000000000000..75548f7c716b
--- /dev/null
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -0,0 +1,3985 @@
+/*
+ * Copyright (c) 2008 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (c) 2008 Eurotech S.p.A. <info@eurtech.it>
+ *
+ * This code is *strongly* based on EHCI-HCD code by David Brownell since
+ * the chip is a quasi-EHCI compatible.
+ *
+ * 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/pci.h>
+#include <linux/dmapool.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/usb.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+
+#include "../core/hcd.h"
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+
+#include "oxu210hp.h"
+
+#define DRIVER_VERSION "0.0.50"
+
+/*
+ * Main defines
+ */
+
+#define oxu_dbg(oxu, fmt, args...) \
+ dev_dbg(oxu_to_hcd(oxu)->self.controller , fmt , ## args)
+#define oxu_err(oxu, fmt, args...) \
+ dev_err(oxu_to_hcd(oxu)->self.controller , fmt , ## args)
+#define oxu_info(oxu, fmt, args...) \
+ dev_info(oxu_to_hcd(oxu)->self.controller , fmt , ## args)
+
+static inline struct usb_hcd *oxu_to_hcd(struct oxu_hcd *oxu)
+{
+ return container_of((void *) oxu, struct usb_hcd, hcd_priv);
+}
+
+static inline struct oxu_hcd *hcd_to_oxu(struct usb_hcd *hcd)
+{
+ return (struct oxu_hcd *) (hcd->hcd_priv);
+}
+
+/*
+ * Debug stuff
+ */
+
+#undef OXU_URB_TRACE
+#undef OXU_VERBOSE_DEBUG
+
+#ifdef OXU_VERBOSE_DEBUG
+#define oxu_vdbg oxu_dbg
+#else
+#define oxu_vdbg(oxu, fmt, args...) /* Nop */
+#endif
+
+#ifdef DEBUG
+
+static int __attribute__((__unused__))
+dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
+{
+ return scnprintf(buf, len, "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
+ label, label[0] ? " " : "", status,
+ (status & STS_ASS) ? " Async" : "",
+ (status & STS_PSS) ? " Periodic" : "",
+ (status & STS_RECL) ? " Recl" : "",
+ (status & STS_HALT) ? " Halt" : "",
+ (status & STS_IAA) ? " IAA" : "",
+ (status & STS_FATAL) ? " FATAL" : "",
+ (status & STS_FLR) ? " FLR" : "",
+ (status & STS_PCD) ? " PCD" : "",
+ (status & STS_ERR) ? " ERR" : "",
+ (status & STS_INT) ? " INT" : ""
+ );
+}
+
+static int __attribute__((__unused__))
+dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
+{
+ return scnprintf(buf, len, "%s%sintrenable %02x%s%s%s%s%s%s",
+ label, label[0] ? " " : "", enable,
+ (enable & STS_IAA) ? " IAA" : "",
+ (enable & STS_FATAL) ? " FATAL" : "",
+ (enable & STS_FLR) ? " FLR" : "",
+ (enable & STS_PCD) ? " PCD" : "",
+ (enable & STS_ERR) ? " ERR" : "",
+ (enable & STS_INT) ? " INT" : ""
+ );
+}
+
+static const char *const fls_strings[] =
+ { "1024", "512", "256", "??" };
+
+static int dbg_command_buf(char *buf, unsigned len,
+ const char *label, u32 command)
+{
+ return scnprintf(buf, len,
+ "%s%scommand %06x %s=%d ithresh=%d%s%s%s%s period=%s%s %s",
+ label, label[0] ? " " : "", command,
+ (command & CMD_PARK) ? "park" : "(park)",
+ CMD_PARK_CNT(command),
+ (command >> 16) & 0x3f,
+ (command & CMD_LRESET) ? " LReset" : "",
+ (command & CMD_IAAD) ? " IAAD" : "",
+ (command & CMD_ASE) ? " Async" : "",
+ (command & CMD_PSE) ? " Periodic" : "",
+ fls_strings[(command >> 2) & 0x3],
+ (command & CMD_RESET) ? " Reset" : "",
+ (command & CMD_RUN) ? "RUN" : "HALT"
+ );
+}
+
+static int dbg_port_buf(char *buf, unsigned len, const char *label,
+ int port, u32 status)
+{
+ char *sig;
+
+ /* signaling state */
+ switch (status & (3 << 10)) {
+ case 0 << 10:
+ sig = "se0";
+ break;
+ case 1 << 10:
+ sig = "k"; /* low speed */
+ break;
+ case 2 << 10:
+ sig = "j";
+ break;
+ default:
+ sig = "?";
+ break;
+ }
+
+ return scnprintf(buf, len,
+ "%s%sport %d status %06x%s%s sig=%s%s%s%s%s%s%s%s%s%s",
+ label, label[0] ? " " : "", port, status,
+ (status & PORT_POWER) ? " POWER" : "",
+ (status & PORT_OWNER) ? " OWNER" : "",
+ sig,
+ (status & PORT_RESET) ? " RESET" : "",
+ (status & PORT_SUSPEND) ? " SUSPEND" : "",
+ (status & PORT_RESUME) ? " RESUME" : "",
+ (status & PORT_OCC) ? " OCC" : "",
+ (status & PORT_OC) ? " OC" : "",
+ (status & PORT_PEC) ? " PEC" : "",
+ (status & PORT_PE) ? " PE" : "",
+ (status & PORT_CSC) ? " CSC" : "",
+ (status & PORT_CONNECT) ? " CONNECT" : ""
+ );
+}
+
+#else
+
+static inline int __attribute__((__unused__))
+dbg_status_buf(char *buf, unsigned len, const char *label, u32 status)
+{ return 0; }
+
+static inline int __attribute__((__unused__))
+dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)
+{ return 0; }
+
+static inline int __attribute__((__unused__))
+dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable)
+{ return 0; }
+
+static inline int __attribute__((__unused__))
+dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)
+{ return 0; }
+
+#endif /* DEBUG */
+
+/* functions have the "wrong" filename when they're output... */
+#define dbg_status(oxu, label, status) { \
+ char _buf[80]; \
+ dbg_status_buf(_buf, sizeof _buf, label, status); \
+ oxu_dbg(oxu, "%s\n", _buf); \
+}
+
+#define dbg_cmd(oxu, label, command) { \
+ char _buf[80]; \
+ dbg_command_buf(_buf, sizeof _buf, label, command); \
+ oxu_dbg(oxu, "%s\n", _buf); \
+}
+
+#define dbg_port(oxu, label, port, status) { \
+ char _buf[80]; \
+ dbg_port_buf(_buf, sizeof _buf, label, port, status); \
+ oxu_dbg(oxu, "%s\n", _buf); \
+}
+
+/*
+ * Module parameters
+ */
+
+/* Initial IRQ latency: faster than hw default */
+static int log2_irq_thresh; /* 0 to 6 */
+module_param(log2_irq_thresh, int, S_IRUGO);
+MODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
+
+/* Initial park setting: slower than hw default */
+static unsigned park;
+module_param(park, uint, S_IRUGO);
+MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets");
+
+/* For flakey hardware, ignore overcurrent indicators */
+static int ignore_oc;
+module_param(ignore_oc, bool, S_IRUGO);
+MODULE_PARM_DESC(ignore_oc, "ignore bogus hardware overcurrent indications");
+
+
+static void ehci_work(struct oxu_hcd *oxu);
+static int oxu_hub_control(struct usb_hcd *hcd,
+ u16 typeReq, u16 wValue, u16 wIndex,
+ char *buf, u16 wLength);
+
+/*
+ * Local functions
+ */
+
+/* Low level read/write registers functions */
+static inline u32 oxu_readl(void *base, u32 reg)
+{
+ return readl(base + reg);
+}
+
+static inline void oxu_writel(void *base, u32 reg, u32 val)
+{
+ writel(val, base + reg);
+}
+
+static inline void timer_action_done(struct oxu_hcd *oxu,
+ enum ehci_timer_action action)
+{
+ clear_bit(action, &oxu->actions);
+}
+
+static inline void timer_action(struct oxu_hcd *oxu,
+ enum ehci_timer_action action)
+{
+ if (!test_and_set_bit(action, &oxu->actions)) {
+ unsigned long t;
+
+ switch (action) {
+ case TIMER_IAA_WATCHDOG:
+ t = EHCI_IAA_JIFFIES;
+ break;
+ case TIMER_IO_WATCHDOG:
+ t = EHCI_IO_JIFFIES;
+ break;
+ case TIMER_ASYNC_OFF:
+ t = EHCI_ASYNC_JIFFIES;
+ break;
+ case TIMER_ASYNC_SHRINK:
+ default:
+ t = EHCI_SHRINK_JIFFIES;
+ break;
+ }
+ t += jiffies;
+ /* all timings except IAA watchdog can be overridden.
+ * async queue SHRINK often precedes IAA. while it's ready
+ * to go OFF neither can matter, and afterwards the IO
+ * watchdog stops unless there's still periodic traffic.
+ */
+ if (action != TIMER_IAA_WATCHDOG
+ && t > oxu->watchdog.expires
+ && timer_pending(&oxu->watchdog))
+ return;
+ mod_timer(&oxu->watchdog, t);
+ }
+}
+
+/*
+ * handshake - spin reading hc until handshake completes or fails
+ * @ptr: address of hc register to be read
+ * @mask: bits to look at in result of read
+ * @done: value of those bits when handshake succeeds
+ * @usec: timeout in microseconds
+ *
+ * Returns negative errno, or zero on success
+ *
+ * Success happens when the "mask" bits have the specified value (hardware
+ * handshake done). There are two failure modes: "usec" have passed (major
+ * hardware flakeout), or the register reads as all-ones (hardware removed).
+ *
+ * That last failure should_only happen in cases like physical cardbus eject
+ * before driver shutdown. But it also seems to be caused by bugs in cardbus
+ * bridge shutdown: shutting down the bridge before the devices using it.
+ */
+static int handshake(struct oxu_hcd *oxu, void __iomem *ptr,
+ u32 mask, u32 done, int usec)
+{
+ u32 result;
+
+ do {
+ result = readl(ptr);
+ if (result == ~(u32)0) /* card removed */
+ return -ENODEV;
+ result &= mask;
+ if (result == done)
+ return 0;
+ udelay(1);
+ usec--;
+ } while (usec > 0);
+ return -ETIMEDOUT;
+}
+
+/* Force HC to halt state from unknown (EHCI spec section 2.3) */
+static int ehci_halt(struct oxu_hcd *oxu)
+{
+ u32 temp = readl(&oxu->regs->status);
+
+ /* disable any irqs left enabled by previous code */
+ writel(0, &oxu->regs->intr_enable);
+
+ if ((temp & STS_HALT) != 0)
+ return 0;
+
+ temp = readl(&oxu->regs->command);
+ temp &= ~CMD_RUN;
+ writel(temp, &oxu->regs->command);
+ return handshake(oxu, &oxu->regs->status,
+ STS_HALT, STS_HALT, 16 * 125);
+}
+
+/* Put TDI/ARC silicon into EHCI mode */
+static void tdi_reset(struct oxu_hcd *oxu)
+{
+ u32 __iomem *reg_ptr;
+ u32 tmp;
+
+ reg_ptr = (u32 __iomem *)(((u8 __iomem *)oxu->regs) + 0x68);
+ tmp = readl(reg_ptr);
+ tmp |= 0x3;
+ writel(tmp, reg_ptr);
+}
+
+/* Reset a non-running (STS_HALT == 1) controller */
+static int ehci_reset(struct oxu_hcd *oxu)
+{
+ int retval;
+ u32 command = readl(&oxu->regs->command);
+
+ command |= CMD_RESET;
+ dbg_cmd(oxu, "reset", command);
+ writel(command, &oxu->regs->command);
+ oxu_to_hcd(oxu)->state = HC_STATE_HALT;
+ oxu->next_statechange = jiffies;
+ retval = handshake(oxu, &oxu->regs->command,
+ CMD_RESET, 0, 250 * 1000);
+
+ if (retval)
+ return retval;
+
+ tdi_reset(oxu);
+
+ return retval;
+}
+
+/* Idle the controller (from running) */
+static void ehci_quiesce(struct oxu_hcd *oxu)
+{
+ u32 temp;
+
+#ifdef DEBUG
+ if (!HC_IS_RUNNING(oxu_to_hcd(oxu)->state))
+ BUG();
+#endif
+
+ /* wait for any schedule enables/disables to take effect */
+ temp = readl(&oxu->regs->command) << 10;
+ temp &= STS_ASS | STS_PSS;
+ if (handshake(oxu, &oxu->regs->status, STS_ASS | STS_PSS,
+ temp, 16 * 125) != 0) {
+ oxu_to_hcd(oxu)->state = HC_STATE_HALT;
+ return;
+ }
+
+ /* then disable anything that's still active */
+ temp = readl(&oxu->regs->command);
+ temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
+ writel(temp, &oxu->regs->command);
+
+ /* hardware can take 16 microframes to turn off ... */
+ if (handshake(oxu, &oxu->regs->status, STS_ASS | STS_PSS,
+ 0, 16 * 125) != 0) {
+ oxu_to_hcd(oxu)->state = HC_STATE_HALT;
+ return;
+ }
+}
+
+static int check_reset_complete(struct oxu_hcd *oxu, int index,
+ u32 __iomem *status_reg, int port_status)
+{
+ if (!(port_status & PORT_CONNECT)) {
+ oxu->reset_done[index] = 0;
+ return port_status;
+ }
+
+ /* if reset finished and it's still not enabled -- handoff */
+ if (!(port_status & PORT_PE)) {
+ oxu_dbg(oxu, "Failed to enable port %d on root hub TT\n",
+ index+1);
+ return port_status;
+ } else
+ oxu_dbg(oxu, "port %d high speed\n", index + 1);
+
+ return port_status;
+}
+
+static void ehci_hub_descriptor(struct oxu_hcd *oxu,
+ struct usb_hub_descriptor *desc)
+{
+ int ports = HCS_N_PORTS(oxu->hcs_params);
+ u16 temp;
+
+ desc->bDescriptorType = 0x29;
+ desc->bPwrOn2PwrGood = 10; /* oxu 1.0, 2.3.9 says 20ms max */
+ desc->bHubContrCurrent = 0;
+
+ desc->bNbrPorts = ports;
+ temp = 1 + (ports / 8);
+ desc->bDescLength = 7 + 2 * temp;
+
+ /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+ memset(&desc->bitmap[0], 0, temp);
+ memset(&desc->bitmap[temp], 0xff, temp);
+
+ temp = 0x0008; /* per-port overcurrent reporting */
+ if (HCS_PPC(oxu->hcs_params))
+ temp |= 0x0001; /* per-port power control */
+ else
+ temp |= 0x0002; /* no power switching */
+ desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp);
+}
+
+
+/* Allocate an OXU210HP on-chip memory data buffer
+ *
+ * An on-chip memory data buffer is required for each OXU210HP USB transfer.
+ * Each transfer descriptor has one or more on-chip memory data buffers.
+ *
+ * Data buffers are allocated from a fix sized pool of data blocks.
+ * To minimise fragmentation and give reasonable memory utlisation,
+ * data buffers are allocated with sizes the power of 2 multiples of
+ * the block size, starting on an address a multiple of the allocated size.
+ *
+ * FIXME: callers of this function require a buffer to be allocated for
+ * len=0. This is a waste of on-chip memory and should be fix. Then this
+ * function should be changed to not allocate a buffer for len=0.
+ */
+static int oxu_buf_alloc(struct oxu_hcd *oxu, struct ehci_qtd *qtd, int len)
+{
+ int n_blocks; /* minium blocks needed to hold len */
+ int a_blocks; /* blocks allocated */
+ int i, j;
+
+ /* Don't allocte bigger than supported */
+ if (len > BUFFER_SIZE * BUFFER_NUM) {
+ oxu_err(oxu, "buffer too big (%d)\n", len);
+ return -ENOMEM;
+ }
+
+ spin_lock(&oxu->mem_lock);
+
+ /* Number of blocks needed to hold len */
+ n_blocks = (len + BUFFER_SIZE - 1) / BUFFER_SIZE;
+
+ /* Round the number of blocks up to the power of 2 */
+ for (a_blocks = 1; a_blocks < n_blocks; a_blocks <<= 1)
+ ;
+
+ /* Find a suitable available data buffer */
+ for (i = 0; i < BUFFER_NUM;
+ i += max(a_blocks, (int)oxu->db_used[i])) {
+
+ /* Check all the required blocks are available */
+ for (j = 0; j < a_blocks; j++)
+ if (oxu->db_used[i + j])
+ break;
+
+ if (j != a_blocks)
+ continue;
+
+ /* Allocate blocks found! */
+ qtd->buffer = (void *) &oxu->mem->db_pool[i];
+ qtd->buffer_dma = virt_to_phys(qtd->buffer);
+
+ qtd->qtd_buffer_len = BUFFER_SIZE * a_blocks;
+ oxu->db_used[i] = a_blocks;
+
+ spin_unlock(&oxu->mem_lock);
+
+ return 0;
+ }
+
+ /* Failed */
+
+ spin_unlock(&oxu->mem_lock);
+
+ return -ENOMEM;
+}
+
+static void oxu_buf_free(struct oxu_hcd *oxu, struct ehci_qtd *qtd)
+{
+ int index;
+
+ spin_lock(&oxu->mem_lock);
+
+ index = (qtd->buffer - (void *) &oxu->mem->db_pool[0])
+ / BUFFER_SIZE;
+ oxu->db_used[index] = 0;
+ qtd->qtd_buffer_len = 0;
+ qtd->buffer_dma = 0;
+ qtd->buffer = NULL;
+
+ spin_unlock(&oxu->mem_lock);
+
+ return;
+}
+
+static inline void ehci_qtd_init(struct ehci_qtd *qtd, dma_addr_t dma)
+{
+ memset(qtd, 0, sizeof *qtd);
+ qtd->qtd_dma = dma;
+ qtd->hw_token = cpu_to_le32(QTD_STS_HALT);
+ qtd->hw_next = EHCI_LIST_END;
+ qtd->hw_alt_next = EHCI_LIST_END;
+ INIT_LIST_HEAD(&qtd->qtd_list);
+}
+
+static inline void oxu_qtd_free(struct oxu_hcd *oxu, struct ehci_qtd *qtd)
+{
+ int index;
+
+ if (qtd->buffer)
+ oxu_buf_free(oxu, qtd);
+
+ spin_lock(&oxu->mem_lock);
+
+ index = qtd - &oxu->mem->qtd_pool[0];
+ oxu->qtd_used[index] = 0;
+
+ spin_unlock(&oxu->mem_lock);
+
+ return;
+}
+
+static struct ehci_qtd *ehci_qtd_alloc(struct oxu_hcd *oxu)
+{
+ int i;
+ struct ehci_qtd *qtd = NULL;
+
+ spin_lock(&oxu->mem_lock);
+
+ for (i = 0; i < QTD_NUM; i++)
+ if (!oxu->qtd_used[i])
+ break;
+
+ if (i < QTD_NUM) {
+ qtd = (struct ehci_qtd *) &oxu->mem->qtd_pool[i];
+ memset(qtd, 0, sizeof *qtd);
+
+ qtd->hw_token = cpu_to_le32(QTD_STS_HALT);
+ qtd->hw_next = EHCI_LIST_END;
+ qtd->hw_alt_next = EHCI_LIST_END;
+ INIT_LIST_HEAD(&qtd->qtd_list);
+
+ qtd->qtd_dma = virt_to_phys(qtd);
+
+ oxu->qtd_used[i] = 1;
+ }
+
+ spin_unlock(&oxu->mem_lock);
+
+ return qtd;
+}
+
+static void oxu_qh_free(struct oxu_hcd *oxu, struct ehci_qh *qh)
+{
+ int index;
+
+ spin_lock(&oxu->mem_lock);
+
+ index = qh - &oxu->mem->qh_pool[0];
+ oxu->qh_used[index] = 0;
+
+ spin_unlock(&oxu->mem_lock);
+
+ return;
+}
+
+static void qh_destroy(struct kref *kref)
+{
+ struct ehci_qh *qh = container_of(kref, struct ehci_qh, kref);
+ struct oxu_hcd *oxu = qh->oxu;
+
+ /* clean qtds first, and know this is not linked */
+ if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) {
+ oxu_dbg(oxu, "unused qh not empty!\n");
+ BUG();
+ }
+ if (qh->dummy)
+ oxu_qtd_free(oxu, qh->dummy);
+ oxu_qh_free(oxu, qh);
+}
+
+static struct ehci_qh *oxu_qh_alloc(struct oxu_hcd *oxu)
+{
+ int i;
+ struct ehci_qh *qh = NULL;
+
+ spin_lock(&oxu->mem_lock);
+
+ for (i = 0; i < QHEAD_NUM; i++)
+ if (!oxu->qh_used[i])
+ break;
+
+ if (i < QHEAD_NUM) {
+ qh = (struct ehci_qh *) &oxu->mem->qh_pool[i];
+ memset(qh, 0, sizeof *qh);
+
+ kref_init(&qh->kref);
+ qh->oxu = oxu;
+ qh->qh_dma = virt_to_phys(qh);
+ INIT_LIST_HEAD(&qh->qtd_list);
+
+ /* dummy td enables safe urb queuing */
+ qh->dummy = ehci_qtd_alloc(oxu);
+ if (qh->dummy == NULL) {
+ oxu_dbg(oxu, "no dummy td\n");
+ oxu->qh_used[i] = 0;
+
+ return NULL;
+ }
+
+ oxu->qh_used[i] = 1;
+ }
+
+ spin_unlock(&oxu->mem_lock);
+
+ return qh;
+}
+
+/* to share a qh (cpu threads, or hc) */
+static inline struct ehci_qh *qh_get(struct ehci_qh *qh)
+{
+ kref_get(&qh->kref);
+ return qh;
+}
+
+static inline void qh_put(struct ehci_qh *qh)
+{
+ kref_put(&qh->kref, qh_destroy);
+}
+
+static void oxu_murb_free(struct oxu_hcd *oxu, struct oxu_murb *murb)
+{
+ int index;
+
+ spin_lock(&oxu->mem_lock);
+
+ index = murb - &oxu->murb_pool[0];
+ oxu->murb_used[index] = 0;
+
+ spin_unlock(&oxu->mem_lock);
+
+ return;
+}
+
+static struct oxu_murb *oxu_murb_alloc(struct oxu_hcd *oxu)
+
+{
+ int i;
+ struct oxu_murb *murb = NULL;
+
+ spin_lock(&oxu->mem_lock);
+
+ for (i = 0; i < MURB_NUM; i++)
+ if (!oxu->murb_used[i])
+ break;
+
+ if (i < MURB_NUM) {
+ murb = &(oxu->murb_pool)[i];
+
+ oxu->murb_used[i] = 1;
+ }
+
+ spin_unlock(&oxu->mem_lock);
+
+ return murb;
+}
+
+/* The queue heads and transfer descriptors are managed from pools tied
+ * to each of the "per device" structures.
+ * This is the initialisation and cleanup code.
+ */
+static void ehci_mem_cleanup(struct oxu_hcd *oxu)
+{
+ kfree(oxu->murb_pool);
+ oxu->murb_pool = NULL;
+
+ if (oxu->async)
+ qh_put(oxu->async);
+ oxu->async = NULL;
+
+ del_timer(&oxu->urb_timer);
+
+ oxu->periodic = NULL;
+
+ /* shadow periodic table */
+ kfree(oxu->pshadow);
+ oxu->pshadow = NULL;
+}
+
+/* Remember to add cleanup code (above) if you add anything here.
+ */
+static int ehci_mem_init(struct oxu_hcd *oxu, gfp_t flags)
+{
+ int i;
+
+ for (i = 0; i < oxu->periodic_size; i++)
+ oxu->mem->frame_list[i] = EHCI_LIST_END;
+ for (i = 0; i < QHEAD_NUM; i++)
+ oxu->qh_used[i] = 0;
+ for (i = 0; i < QTD_NUM; i++)
+ oxu->qtd_used[i] = 0;
+
+ oxu->murb_pool = kcalloc(MURB_NUM, sizeof(struct oxu_murb), flags);
+ if (!oxu->murb_pool)
+ goto fail;
+
+ for (i = 0; i < MURB_NUM; i++)
+ oxu->murb_used[i] = 0;
+
+ oxu->async = oxu_qh_alloc(oxu);
+ if (!oxu->async)
+ goto fail;
+
+ oxu->periodic = (__le32 *) &oxu->mem->frame_list;
+ oxu->periodic_dma = virt_to_phys(oxu->periodic);
+
+ for (i = 0; i < oxu->periodic_size; i++)
+ oxu->periodic[i] = EHCI_LIST_END;
+
+ /* software shadow of hardware table */
+ oxu->pshadow = kcalloc(oxu->periodic_size, sizeof(void *), flags);
+ if (oxu->pshadow != NULL)
+ return 0;
+
+fail:
+ oxu_dbg(oxu, "couldn't init memory\n");
+ ehci_mem_cleanup(oxu);
+ return -ENOMEM;
+}
+
+/* Fill a qtd, returning how much of the buffer we were able to queue up.
+ */
+static int qtd_fill(struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
+ int token, int maxpacket)
+{
+ int i, count;
+ u64 addr = buf;
+
+ /* one buffer entry per 4K ... first might be short or unaligned */
+ qtd->hw_buf[0] = cpu_to_le32((u32)addr);
+ qtd->hw_buf_hi[0] = cpu_to_le32((u32)(addr >> 32));
+ count = 0x1000 - (buf & 0x0fff); /* rest of that page */
+ if (likely(len < count)) /* ... iff needed */
+ count = len;
+ else {
+ buf += 0x1000;
+ buf &= ~0x0fff;
+
+ /* per-qtd limit: from 16K to 20K (best alignment) */
+ for (i = 1; count < len && i < 5; i++) {
+ addr = buf;
+ qtd->hw_buf[i] = cpu_to_le32((u32)addr);
+ qtd->hw_buf_hi[i] = cpu_to_le32((u32)(addr >> 32));
+ buf += 0x1000;
+ if ((count + 0x1000) < len)
+ count += 0x1000;
+ else
+ count = len;
+ }
+
+ /* short packets may only terminate transfers */
+ if (count != len)
+ count -= (count % maxpacket);
+ }
+ qtd->hw_token = cpu_to_le32((count << 16) | token);
+ qtd->length = count;
+
+ return count;
+}
+
+static inline void qh_update(struct oxu_hcd *oxu,
+ struct ehci_qh *qh, struct ehci_qtd *qtd)
+{
+ /* writes to an active overlay are unsafe */
+ BUG_ON(qh->qh_state != QH_STATE_IDLE);
+
+ qh->hw_qtd_next = QTD_NEXT(qtd->qtd_dma);
+ qh->hw_alt_next = EHCI_LIST_END;
+
+ /* Except for control endpoints, we make hardware maintain data
+ * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
+ * and set the pseudo-toggle in udev. Only usb_clear_halt() will
+ * ever clear it.
+ */
+ if (!(qh->hw_info1 & cpu_to_le32(1 << 14))) {
+ unsigned is_out, epnum;
+
+ is_out = !(qtd->hw_token & cpu_to_le32(1 << 8));
+ epnum = (le32_to_cpup(&qh->hw_info1) >> 8) & 0x0f;
+ if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) {
+ qh->hw_token &= ~__constant_cpu_to_le32(QTD_TOGGLE);
+ usb_settoggle(qh->dev, epnum, is_out, 1);
+ }
+ }
+
+ /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
+ wmb();
+ qh->hw_token &= __constant_cpu_to_le32(QTD_TOGGLE | QTD_STS_PING);
+}
+
+/* If it weren't for a common silicon quirk (writing the dummy into the qh
+ * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
+ * recovery (including urb dequeue) would need software changes to a QH...
+ */
+static void qh_refresh(struct oxu_hcd *oxu, struct ehci_qh *qh)
+{
+ struct ehci_qtd *qtd;
+
+ if (list_empty(&qh->qtd_list))
+ qtd = qh->dummy;
+ else {
+ qtd = list_entry(qh->qtd_list.next,
+ struct ehci_qtd, qtd_list);
+ /* first qtd may already be partially processed */
+ if (cpu_to_le32(qtd->qtd_dma) == qh->hw_current)
+ qtd = NULL;
+ }
+
+ if (qtd)
+ qh_update(oxu, qh, qtd);
+}
+
+static void qtd_copy_status(struct oxu_hcd *oxu, struct urb *urb,
+ size_t length, u32 token)
+{
+ /* count IN/OUT bytes, not SETUP (even short packets) */
+ if (likely(QTD_PID(token) != 2))
+ urb->actual_length += length - QTD_LENGTH(token);
+
+ /* don't modify error codes */
+ if (unlikely(urb->status != -EINPROGRESS))
+ return;
+
+ /* force cleanup after short read; not always an error */
+ if (unlikely(IS_SHORT_READ(token)))
+ urb->status = -EREMOTEIO;
+
+ /* serious "can't proceed" faults reported by the hardware */
+ if (token & QTD_STS_HALT) {
+ if (token & QTD_STS_BABBLE) {
+ /* FIXME "must" disable babbling device's port too */
+ urb->status = -EOVERFLOW;
+ } else if (token & QTD_STS_MMF) {
+ /* fs/ls interrupt xfer missed the complete-split */
+ urb->status = -EPROTO;
+ } else if (token & QTD_STS_DBE) {
+ urb->status = (QTD_PID(token) == 1) /* IN ? */
+ ? -ENOSR /* hc couldn't read data */
+ : -ECOMM; /* hc couldn't write data */
+ } else if (token & QTD_STS_XACT) {
+ /* timeout, bad crc, wrong PID, etc; retried */
+ if (QTD_CERR(token))
+ urb->status = -EPIPE;
+ else {
+ oxu_dbg(oxu, "devpath %s ep%d%s 3strikes\n",
+ urb->dev->devpath,
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out");
+ urb->status = -EPROTO;
+ }
+ /* CERR nonzero + no errors + halt --> stall */
+ } else if (QTD_CERR(token))
+ urb->status = -EPIPE;
+ else /* unknown */
+ urb->status = -EPROTO;
+
+ oxu_vdbg(oxu, "dev%d ep%d%s qtd token %08x --> status %d\n",
+ usb_pipedevice(urb->pipe),
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
+ token, urb->status);
+ }
+}
+
+static void ehci_urb_done(struct oxu_hcd *oxu, struct urb *urb)
+__releases(oxu->lock)
+__acquires(oxu->lock)
+{
+ if (likely(urb->hcpriv != NULL)) {
+ struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
+
+ /* S-mask in a QH means it's an interrupt urb */
+ if ((qh->hw_info2 & __constant_cpu_to_le32(QH_SMASK)) != 0) {
+
+ /* ... update hc-wide periodic stats (for usbfs) */
+ oxu_to_hcd(oxu)->self.bandwidth_int_reqs--;
+ }
+ qh_put(qh);
+ }
+
+ urb->hcpriv = NULL;
+ switch (urb->status) {
+ case -EINPROGRESS: /* success */
+ urb->status = 0;
+ default: /* fault */
+ break;
+ case -EREMOTEIO: /* fault or normal */
+ if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
+ urb->status = 0;
+ break;
+ case -ECONNRESET: /* canceled */
+ case -ENOENT:
+ break;
+ }
+
+#ifdef OXU_URB_TRACE
+ oxu_dbg(oxu, "%s %s urb %p ep%d%s status %d len %d/%d\n",
+ __func__, urb->dev->devpath, urb,
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
+ urb->status,
+ urb->actual_length, urb->transfer_buffer_length);
+#endif
+
+ /* complete() can reenter this HCD */
+ spin_unlock(&oxu->lock);
+ usb_hcd_giveback_urb(oxu_to_hcd(oxu), urb, urb->status);
+ spin_lock(&oxu->lock);
+}
+
+static void start_unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh);
+static void unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh);
+
+static void intr_deschedule(struct oxu_hcd *oxu, struct ehci_qh *qh);
+static int qh_schedule(struct oxu_hcd *oxu, struct ehci_qh *qh);
+
+#define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
+
+/* Process and free completed qtds for a qh, returning URBs to drivers.
+ * Chases up to qh->hw_current. Returns number of completions called,
+ * indicating how much "real" work we did.
+ */
+static unsigned qh_completions(struct oxu_hcd *oxu, struct ehci_qh *qh)
+{
+ struct ehci_qtd *last = NULL, *end = qh->dummy;
+ struct list_head *entry, *tmp;
+ int stopped;
+ unsigned count = 0;
+ int do_status = 0;
+ u8 state;
+ struct oxu_murb *murb = NULL;
+
+ if (unlikely(list_empty(&qh->qtd_list)))
+ return count;
+
+ /* completions (or tasks on other cpus) must never clobber HALT
+ * till we've gone through and cleaned everything up, even when
+ * they add urbs to this qh's queue or mark them for unlinking.
+ *
+ * NOTE: unlinking expects to be done in queue order.
+ */
+ state = qh->qh_state;
+ qh->qh_state = QH_STATE_COMPLETING;
+ stopped = (state == QH_STATE_IDLE);
+
+ /* remove de-activated QTDs from front of queue.
+ * after faults (including short reads), cleanup this urb
+ * then let the queue advance.
+ * if queue is stopped, handles unlinks.
+ */
+ list_for_each_safe(entry, tmp, &qh->qtd_list) {
+ struct ehci_qtd *qtd;
+ struct urb *urb;
+ u32 token = 0;
+
+ qtd = list_entry(entry, struct ehci_qtd, qtd_list);
+ urb = qtd->urb;
+
+ /* Clean up any state from previous QTD ...*/
+ if (last) {
+ if (likely(last->urb != urb)) {
+ if (last->urb->complete == NULL) {
+ murb = (struct oxu_murb *) last->urb;
+ last->urb = murb->main;
+ if (murb->last) {
+ ehci_urb_done(oxu, last->urb);
+ count++;
+ }
+ oxu_murb_free(oxu, murb);
+ } else {
+ ehci_urb_done(oxu, last->urb);
+ count++;
+ }
+ }
+ oxu_qtd_free(oxu, last);
+ last = NULL;
+ }
+
+ /* ignore urbs submitted during completions we reported */
+ if (qtd == end)
+ break;
+
+ /* hardware copies qtd out of qh overlay */
+ rmb();
+ token = le32_to_cpu(qtd->hw_token);
+
+ /* always clean up qtds the hc de-activated */
+ if ((token & QTD_STS_ACTIVE) == 0) {
+
+ if ((token & QTD_STS_HALT) != 0) {
+ stopped = 1;
+
+ /* magic dummy for some short reads; qh won't advance.
+ * that silicon quirk can kick in with this dummy too.
+ */
+ } else if (IS_SHORT_READ(token) &&
+ !(qtd->hw_alt_next & EHCI_LIST_END)) {
+ stopped = 1;
+ goto halt;
+ }
+
+ /* stop scanning when we reach qtds the hc is using */
+ } else if (likely(!stopped &&
+ HC_IS_RUNNING(oxu_to_hcd(oxu)->state))) {
+ break;
+
+ } else {
+ stopped = 1;
+
+ if (unlikely(!HC_IS_RUNNING(oxu_to_hcd(oxu)->state)))
+ urb->status = -ESHUTDOWN;
+
+ /* ignore active urbs unless some previous qtd
+ * for the urb faulted (including short read) or
+ * its urb was canceled. we may patch qh or qtds.
+ */
+ if (likely(urb->status == -EINPROGRESS))
+ continue;
+
+ /* issue status after short control reads */
+ if (unlikely(do_status != 0)
+ && QTD_PID(token) == 0 /* OUT */) {
+ do_status = 0;
+ continue;
+ }
+
+ /* token in overlay may be most current */
+ if (state == QH_STATE_IDLE
+ && cpu_to_le32(qtd->qtd_dma)
+ == qh->hw_current)
+ token = le32_to_cpu(qh->hw_token);
+
+ /* force halt for unlinked or blocked qh, so we'll
+ * patch the qh later and so that completions can't
+ * activate it while we "know" it's stopped.
+ */
+ if ((HALT_BIT & qh->hw_token) == 0) {
+halt:
+ qh->hw_token |= HALT_BIT;
+ wmb();
+ }
+ }
+
+ /* Remove it from the queue */
+ qtd_copy_status(oxu, urb->complete ?
+ urb : ((struct oxu_murb *) urb)->main,
+ qtd->length, token);
+ if ((usb_pipein(qtd->urb->pipe)) &&
+ (NULL != qtd->transfer_buffer))
+ memcpy(qtd->transfer_buffer, qtd->buffer, qtd->length);
+ do_status = (urb->status == -EREMOTEIO)
+ && usb_pipecontrol(urb->pipe);
+
+ if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
+ last = list_entry(qtd->qtd_list.prev,
+ struct ehci_qtd, qtd_list);
+ last->hw_next = qtd->hw_next;
+ }
+ list_del(&qtd->qtd_list);
+ last = qtd;
+ }
+
+ /* last urb's completion might still need calling */
+ if (likely(last != NULL)) {
+ if (last->urb->complete == NULL) {
+ murb = (struct oxu_murb *) last->urb;
+ last->urb = murb->main;
+ if (murb->last) {
+ ehci_urb_done(oxu, last->urb);
+ count++;
+ }
+ oxu_murb_free(oxu, murb);
+ } else {
+ ehci_urb_done(oxu, last->urb);
+ count++;
+ }
+ oxu_qtd_free(oxu, last);
+ }
+
+ /* restore original state; caller must unlink or relink */
+ qh->qh_state = state;
+
+ /* be sure the hardware's done with the qh before refreshing
+ * it after fault cleanup, or recovering from silicon wrongly
+ * overlaying the dummy qtd (which reduces DMA chatter).
+ */
+ if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END) {
+ switch (state) {
+ case QH_STATE_IDLE:
+ qh_refresh(oxu, qh);
+ break;
+ case QH_STATE_LINKED:
+ /* should be rare for periodic transfers,
+ * except maybe high bandwidth ...
+ */
+ if ((__constant_cpu_to_le32(QH_SMASK)
+ & qh->hw_info2) != 0) {
+ intr_deschedule(oxu, qh);
+ (void) qh_schedule(oxu, qh);
+ } else
+ unlink_async(oxu, qh);
+ break;
+ /* otherwise, unlink already started */
+ }
+ }
+
+ return count;
+}
+
+/* High bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+/* ... and packet size, for any kind of endpoint descriptor */
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+
+/* Reverse of qh_urb_transaction: free a list of TDs.
+ * used for cleanup after errors, before HC sees an URB's TDs.
+ */
+static void qtd_list_free(struct oxu_hcd *oxu,
+ struct urb *urb, struct list_head *qtd_list)
+{
+ struct list_head *entry, *temp;
+
+ list_for_each_safe(entry, temp, qtd_list) {
+ struct ehci_qtd *qtd;
+
+ qtd = list_entry(entry, struct ehci_qtd, qtd_list);
+ list_del(&qtd->qtd_list);
+ oxu_qtd_free(oxu, qtd);
+ }
+}
+
+/* Create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *qh_urb_transaction(struct oxu_hcd *oxu,
+ struct urb *urb,
+ struct list_head *head,
+ gfp_t flags)
+{
+ struct ehci_qtd *qtd, *qtd_prev;
+ dma_addr_t buf;
+ int len, maxpacket;
+ int is_input;
+ u32 token;
+ void *transfer_buf = NULL;
+ int ret;
+
+ /*
+ * URBs map to sequences of QTDs: one logical transaction
+ */
+ qtd = ehci_qtd_alloc(oxu);
+ if (unlikely(!qtd))
+ return NULL;
+ list_add_tail(&qtd->qtd_list, head);
+ qtd->urb = urb;
+
+ token = QTD_STS_ACTIVE;
+ token |= (EHCI_TUNE_CERR << 10);
+ /* for split transactions, SplitXState initialized to zero */
+
+ len = urb->transfer_buffer_length;
+ is_input = usb_pipein(urb->pipe);
+ if (!urb->transfer_buffer && urb->transfer_buffer_length && is_input)
+ urb->transfer_buffer = phys_to_virt(urb->transfer_dma);
+
+ if (usb_pipecontrol(urb->pipe)) {
+ /* SETUP pid */
+ ret = oxu_buf_alloc(oxu, qtd, sizeof(struct usb_ctrlrequest));
+ if (ret)
+ goto cleanup;
+
+ qtd_fill(qtd, qtd->buffer_dma, sizeof(struct usb_ctrlrequest),
+ token | (2 /* "setup" */ << 8), 8);
+ memcpy(qtd->buffer, qtd->urb->setup_packet,
+ sizeof(struct usb_ctrlrequest));
+
+ /* ... and always at least one more pid */
+ token ^= QTD_TOGGLE;
+ qtd_prev = qtd;
+ qtd = ehci_qtd_alloc(oxu);
+ if (unlikely(!qtd))
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = QTD_NEXT(qtd->qtd_dma);
+ list_add_tail(&qtd->qtd_list, head);
+
+ /* for zero length DATA stages, STATUS is always IN */
+ if (len == 0)
+ token |= (1 /* "in" */ << 8);
+ }
+
+ /*
+ * Data transfer stage: buffer setup
+ */
+
+ ret = oxu_buf_alloc(oxu, qtd, len);
+ if (ret)
+ goto cleanup;
+
+ buf = qtd->buffer_dma;
+ transfer_buf = urb->transfer_buffer;
+
+ if (!is_input)
+ memcpy(qtd->buffer, qtd->urb->transfer_buffer, len);
+
+ if (is_input)
+ token |= (1 /* "in" */ << 8);
+ /* else it's already initted to "out" pid (0 << 8) */
+
+ maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
+
+ /*
+ * buffer gets wrapped in one or more qtds;
+ * last one may be "short" (including zero len)
+ * and may serve as a control status ack
+ */
+ for (;;) {
+ int this_qtd_len;
+
+ this_qtd_len = qtd_fill(qtd, buf, len, token, maxpacket);
+ qtd->transfer_buffer = transfer_buf;
+ len -= this_qtd_len;
+ buf += this_qtd_len;
+ transfer_buf += this_qtd_len;
+ if (is_input)
+ qtd->hw_alt_next = oxu->async->hw_alt_next;
+
+ /* qh makes control packets use qtd toggle; maybe switch it */
+ if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+ token ^= QTD_TOGGLE;
+
+ if (likely(len <= 0))
+ break;
+
+ qtd_prev = qtd;
+ qtd = ehci_qtd_alloc(oxu);
+ if (unlikely(!qtd))
+ goto cleanup;
+ if (likely(len > 0)) {
+ ret = oxu_buf_alloc(oxu, qtd, len);
+ if (ret)
+ goto cleanup;
+ }
+ qtd->urb = urb;
+ qtd_prev->hw_next = QTD_NEXT(qtd->qtd_dma);
+ list_add_tail(&qtd->qtd_list, head);
+ }
+
+ /* unless the bulk/interrupt caller wants a chance to clean
+ * up after short reads, hc should advance qh past this urb
+ */
+ if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
+ || usb_pipecontrol(urb->pipe)))
+ qtd->hw_alt_next = EHCI_LIST_END;
+
+ /*
+ * control requests may need a terminating data "status" ack;
+ * bulk ones may need a terminating short packet (zero length).
+ */
+ if (likely(urb->transfer_buffer_length != 0)) {
+ int one_more = 0;
+
+ if (usb_pipecontrol(urb->pipe)) {
+ one_more = 1;
+ token ^= 0x0100; /* "in" <--> "out" */
+ token |= QTD_TOGGLE; /* force DATA1 */
+ } else if (usb_pipebulk(urb->pipe)
+ && (urb->transfer_flags & URB_ZERO_PACKET)
+ && !(urb->transfer_buffer_length % maxpacket)) {
+ one_more = 1;
+ }
+ if (one_more) {
+ qtd_prev = qtd;
+ qtd = ehci_qtd_alloc(oxu);
+ if (unlikely(!qtd))
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = QTD_NEXT(qtd->qtd_dma);
+ list_add_tail(&qtd->qtd_list, head);
+
+ /* never any data in such packets */
+ qtd_fill(qtd, 0, 0, token, 0);
+ }
+ }
+
+ /* by default, enable interrupt on urb completion */
+ qtd->hw_token |= __constant_cpu_to_le32(QTD_IOC);
+ return head;
+
+cleanup:
+ qtd_list_free(oxu, urb, head);
+ return NULL;
+}
+
+/* Each QH holds a qtd list; a QH is used for everything except iso.
+ *
+ * For interrupt urbs, the scheduler must set the microframe scheduling
+ * mask(s) each time the QH gets scheduled. For highspeed, that's
+ * just one microframe in the s-mask. For split interrupt transactions
+ * there are additional complications: c-mask, maybe FSTNs.
+ */
+static struct ehci_qh *qh_make(struct oxu_hcd *oxu,
+ struct urb *urb, gfp_t flags)
+{
+ struct ehci_qh *qh = oxu_qh_alloc(oxu);
+ u32 info1 = 0, info2 = 0;
+ int is_input, type;
+ int maxp = 0;
+
+ if (!qh)
+ return qh;
+
+ /*
+ * init endpoint/device data for this QH
+ */
+ info1 |= usb_pipeendpoint(urb->pipe) << 8;
+ info1 |= usb_pipedevice(urb->pipe) << 0;
+
+ is_input = usb_pipein(urb->pipe);
+ type = usb_pipetype(urb->pipe);
+ maxp = usb_maxpacket(urb->dev, urb->pipe, !is_input);
+
+ /* Compute interrupt scheduling parameters just once, and save.
+ * - allowing for high bandwidth, how many nsec/uframe are used?
+ * - split transactions need a second CSPLIT uframe; same question
+ * - splits also need a schedule gap (for full/low speed I/O)
+ * - qh has a polling interval
+ *
+ * For control/bulk requests, the HC or TT handles these.
+ */
+ if (type == PIPE_INTERRUPT) {
+ qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
+ is_input, 0,
+ hb_mult(maxp) * max_packet(maxp)));
+ qh->start = NO_FRAME;
+
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+ qh->c_usecs = 0;
+ qh->gap_uf = 0;
+
+ qh->period = urb->interval >> 3;
+ if (qh->period == 0 && urb->interval != 1) {
+ /* NOTE interval 2 or 4 uframes could work.
+ * But interval 1 scheduling is simpler, and
+ * includes high bandwidth.
+ */
+ dbg("intr period %d uframes, NYET!",
+ urb->interval);
+ goto done;
+ }
+ } else {
+ struct usb_tt *tt = urb->dev->tt;
+ int think_time;
+
+ /* gap is f(FS/LS transfer times) */
+ qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed,
+ is_input, 0, maxp) / (125 * 1000);
+
+ /* FIXME this just approximates SPLIT/CSPLIT times */
+ if (is_input) { /* SPLIT, gap, CSPLIT+DATA */
+ qh->c_usecs = qh->usecs + HS_USECS(0);
+ qh->usecs = HS_USECS(1);
+ } else { /* SPLIT+DATA, gap, CSPLIT */
+ qh->usecs += HS_USECS(1);
+ qh->c_usecs = HS_USECS(0);
+ }
+
+ think_time = tt ? tt->think_time : 0;
+ qh->tt_usecs = NS_TO_US(think_time +
+ usb_calc_bus_time(urb->dev->speed,
+ is_input, 0, max_packet(maxp)));
+ qh->period = urb->interval;
+ }
+ }
+
+ /* support for tt scheduling, and access to toggles */
+ qh->dev = urb->dev;
+
+ /* using TT? */
+ switch (urb->dev->speed) {
+ case USB_SPEED_LOW:
+ info1 |= (1 << 12); /* EPS "low" */
+ /* FALL THROUGH */
+
+ case USB_SPEED_FULL:
+ /* EPS 0 means "full" */
+ if (type != PIPE_INTERRUPT)
+ info1 |= (EHCI_TUNE_RL_TT << 28);
+ if (type == PIPE_CONTROL) {
+ info1 |= (1 << 27); /* for TT */
+ info1 |= 1 << 14; /* toggle from qtd */
+ }
+ info1 |= maxp << 16;
+
+ info2 |= (EHCI_TUNE_MULT_TT << 30);
+ info2 |= urb->dev->ttport << 23;
+
+ /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */
+
+ break;
+
+ case USB_SPEED_HIGH: /* no TT involved */
+ info1 |= (2 << 12); /* EPS "high" */
+ if (type == PIPE_CONTROL) {
+ info1 |= (EHCI_TUNE_RL_HS << 28);
+ info1 |= 64 << 16; /* usb2 fixed maxpacket */
+ info1 |= 1 << 14; /* toggle from qtd */
+ info2 |= (EHCI_TUNE_MULT_HS << 30);
+ } else if (type == PIPE_BULK) {
+ info1 |= (EHCI_TUNE_RL_HS << 28);
+ info1 |= 512 << 16; /* usb2 fixed maxpacket */
+ info2 |= (EHCI_TUNE_MULT_HS << 30);
+ } else { /* PIPE_INTERRUPT */
+ info1 |= max_packet(maxp) << 16;
+ info2 |= hb_mult(maxp) << 30;
+ }
+ break;
+ default:
+ dbg("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+done:
+ qh_put(qh);
+ return NULL;
+ }
+
+ /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */
+
+ /* init as live, toggle clear, advance to dummy */
+ qh->qh_state = QH_STATE_IDLE;
+ qh->hw_info1 = cpu_to_le32(info1);
+ qh->hw_info2 = cpu_to_le32(info2);
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1);
+ qh_refresh(oxu, qh);
+ return qh;
+}
+
+/* Move qh (and its qtds) onto async queue; maybe enable queue.
+ */
+static void qh_link_async(struct oxu_hcd *oxu, struct ehci_qh *qh)
+{
+ __le32 dma = QH_NEXT(qh->qh_dma);
+ struct ehci_qh *head;
+
+ /* (re)start the async schedule? */
+ head = oxu->async;
+ timer_action_done(oxu, TIMER_ASYNC_OFF);
+ if (!head->qh_next.qh) {
+ u32 cmd = readl(&oxu->regs->command);
+
+ if (!(cmd & CMD_ASE)) {
+ /* in case a clear of CMD_ASE didn't take yet */
+ (void)handshake(oxu, &oxu->regs->status,
+ STS_ASS, 0, 150);
+ cmd |= CMD_ASE | CMD_RUN;
+ writel(cmd, &oxu->regs->command);
+ oxu_to_hcd(oxu)->state = HC_STATE_RUNNING;
+ /* posted write need not be known to HC yet ... */
+ }
+ }
+
+ /* clear halt and/or toggle; and maybe recover from silicon quirk */
+ if (qh->qh_state == QH_STATE_IDLE)
+ qh_refresh(oxu, qh);
+
+ /* splice right after start */
+ qh->qh_next = head->qh_next;
+ qh->hw_next = head->hw_next;
+ wmb();
+
+ head->qh_next.qh = qh;
+ head->hw_next = dma;
+
+ qh->qh_state = QH_STATE_LINKED;
+ /* qtd completions reported later by interrupt */
+}
+
+#define QH_ADDR_MASK __constant_cpu_to_le32(0x7f)
+
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct ehci_qh *qh_append_tds(struct oxu_hcd *oxu,
+ struct urb *urb, struct list_head *qtd_list,
+ int epnum, void **ptr)
+{
+ struct ehci_qh *qh = NULL;
+
+ qh = (struct ehci_qh *) *ptr;
+ if (unlikely(qh == NULL)) {
+ /* can't sleep here, we have oxu->lock... */
+ qh = qh_make(oxu, urb, GFP_ATOMIC);
+ *ptr = qh;
+ }
+ if (likely(qh != NULL)) {
+ struct ehci_qtd *qtd;
+
+ if (unlikely(list_empty(qtd_list)))
+ qtd = NULL;
+ else
+ qtd = list_entry(qtd_list->next, struct ehci_qtd,
+ qtd_list);
+
+ /* control qh may need patching ... */
+ if (unlikely(epnum == 0)) {
+
+ /* usb_reset_device() briefly reverts to address 0 */
+ if (usb_pipedevice(urb->pipe) == 0)
+ qh->hw_info1 &= ~QH_ADDR_MASK;
+ }
+
+ /* just one way to queue requests: swap with the dummy qtd.
+ * only hc or qh_refresh() ever modify the overlay.
+ */
+ if (likely(qtd != NULL)) {
+ struct ehci_qtd *dummy;
+ dma_addr_t dma;
+ __le32 token;
+
+ /* to avoid racing the HC, use the dummy td instead of
+ * the first td of our list (becomes new dummy). both
+ * tds stay deactivated until we're done, when the
+ * HC is allowed to fetch the old dummy (4.10.2).
+ */
+ token = qtd->hw_token;
+ qtd->hw_token = HALT_BIT;
+ wmb();
+ dummy = qh->dummy;
+
+ dma = dummy->qtd_dma;
+ *dummy = *qtd;
+ dummy->qtd_dma = dma;
+
+ list_del(&qtd->qtd_list);
+ list_add(&dummy->qtd_list, qtd_list);
+ list_splice(qtd_list, qh->qtd_list.prev);
+
+ ehci_qtd_init(qtd, qtd->qtd_dma);
+ qh->dummy = qtd;
+
+ /* hc must see the new dummy at list end */
+ dma = qtd->qtd_dma;
+ qtd = list_entry(qh->qtd_list.prev,
+ struct ehci_qtd, qtd_list);
+ qtd->hw_next = QTD_NEXT(dma);
+
+ /* let the hc process these next qtds */
+ dummy->hw_token = (token & ~(0x80));
+ wmb();
+ dummy->hw_token = token;
+
+ urb->hcpriv = qh_get(qh);
+ }
+ }
+ return qh;
+}
+
+static int submit_async(struct oxu_hcd *oxu, struct urb *urb,
+ struct list_head *qtd_list, gfp_t mem_flags)
+{
+ struct ehci_qtd *qtd;
+ int epnum;
+ unsigned long flags;
+ struct ehci_qh *qh = NULL;
+ int rc = 0;
+
+ qtd = list_entry(qtd_list->next, struct ehci_qtd, qtd_list);
+ epnum = urb->ep->desc.bEndpointAddress;
+
+#ifdef OXU_URB_TRACE
+ oxu_dbg(oxu, "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
+ __func__, urb->dev->devpath, urb,
+ epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
+ urb->transfer_buffer_length,
+ qtd, urb->ep->hcpriv);
+#endif
+
+ spin_lock_irqsave(&oxu->lock, flags);
+ if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
+ &oxu_to_hcd(oxu)->flags))) {
+ rc = -ESHUTDOWN;
+ goto done;
+ }
+
+ qh = qh_append_tds(oxu, urb, qtd_list, epnum, &urb->ep->hcpriv);
+ if (unlikely(qh == NULL)) {
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ /* Control/bulk operations through TTs don't need scheduling,
+ * the HC and TT handle it when the TT has a buffer ready.
+ */
+ if (likely(qh->qh_state == QH_STATE_IDLE))
+ qh_link_async(oxu, qh_get(qh));
+done:
+ spin_unlock_irqrestore(&oxu->lock, flags);
+ if (unlikely(qh == NULL))
+ qtd_list_free(oxu, urb, qtd_list);
+ return rc;
+}
+
+/* The async qh for the qtds being reclaimed are now unlinked from the HC */
+
+static void end_unlink_async(struct oxu_hcd *oxu)
+{
+ struct ehci_qh *qh = oxu->reclaim;
+ struct ehci_qh *next;
+
+ timer_action_done(oxu, TIMER_IAA_WATCHDOG);
+
+ qh->qh_state = QH_STATE_IDLE;
+ qh->qh_next.qh = NULL;
+ qh_put(qh); /* refcount from reclaim */
+
+ /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
+ next = qh->reclaim;
+ oxu->reclaim = next;
+ oxu->reclaim_ready = 0;
+ qh->reclaim = NULL;
+
+ qh_completions(oxu, qh);
+
+ if (!list_empty(&qh->qtd_list)
+ && HC_IS_RUNNING(oxu_to_hcd(oxu)->state))
+ qh_link_async(oxu, qh);
+ else {
+ qh_put(qh); /* refcount from async list */
+
+ /* it's not free to turn the async schedule on/off; leave it
+ * active but idle for a while once it empties.
+ */
+ if (HC_IS_RUNNING(oxu_to_hcd(oxu)->state)
+ && oxu->async->qh_next.qh == NULL)
+ timer_action(oxu, TIMER_ASYNC_OFF);
+ }
+
+ if (next) {
+ oxu->reclaim = NULL;
+ start_unlink_async(oxu, next);
+ }
+}
+
+/* makes sure the async qh will become idle */
+/* caller must own oxu->lock */
+
+static void start_unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh)
+{
+ int cmd = readl(&oxu->regs->command);
+ struct ehci_qh *prev;
+
+#ifdef DEBUG
+ assert_spin_locked(&oxu->lock);
+ if (oxu->reclaim || (qh->qh_state != QH_STATE_LINKED
+ && qh->qh_state != QH_STATE_UNLINK_WAIT))
+ BUG();
+#endif
+
+ /* stop async schedule right now? */
+ if (unlikely(qh == oxu->async)) {
+ /* can't get here without STS_ASS set */
+ if (oxu_to_hcd(oxu)->state != HC_STATE_HALT
+ && !oxu->reclaim) {
+ /* ... and CMD_IAAD clear */
+ writel(cmd & ~CMD_ASE, &oxu->regs->command);
+ wmb();
+ /* handshake later, if we need to */
+ timer_action_done(oxu, TIMER_ASYNC_OFF);
+ }
+ return;
+ }
+
+ qh->qh_state = QH_STATE_UNLINK;
+ oxu->reclaim = qh = qh_get(qh);
+
+ prev = oxu->async;
+ while (prev->qh_next.qh != qh)
+ prev = prev->qh_next.qh;
+
+ prev->hw_next = qh->hw_next;
+ prev->qh_next = qh->qh_next;
+ wmb();
+
+ if (unlikely(oxu_to_hcd(oxu)->state == HC_STATE_HALT)) {
+ /* if (unlikely(qh->reclaim != 0))
+ * this will recurse, probably not much
+ */
+ end_unlink_async(oxu);
+ return;
+ }
+
+ oxu->reclaim_ready = 0;
+ cmd |= CMD_IAAD;
+ writel(cmd, &oxu->regs->command);
+ (void) readl(&oxu->regs->command);
+ timer_action(oxu, TIMER_IAA_WATCHDOG);
+}
+
+static void scan_async(struct oxu_hcd *oxu)
+{
+ struct ehci_qh *qh;
+ enum ehci_timer_action action = TIMER_IO_WATCHDOG;
+
+ if (!++(oxu->stamp))
+ oxu->stamp++;
+ timer_action_done(oxu, TIMER_ASYNC_SHRINK);
+rescan:
+ qh = oxu->async->qh_next.qh;
+ if (likely(qh != NULL)) {
+ do {
+ /* clean any finished work for this qh */
+ if (!list_empty(&qh->qtd_list)
+ && qh->stamp != oxu->stamp) {
+ int temp;
+
+ /* unlinks could happen here; completion
+ * reporting drops the lock. rescan using
+ * the latest schedule, but don't rescan
+ * qhs we already finished (no looping).
+ */
+ qh = qh_get(qh);
+ qh->stamp = oxu->stamp;
+ temp = qh_completions(oxu, qh);
+ qh_put(qh);
+ if (temp != 0)
+ goto rescan;
+ }
+
+ /* unlink idle entries, reducing HC PCI usage as well
+ * as HCD schedule-scanning costs. delay for any qh
+ * we just scanned, there's a not-unusual case that it
+ * doesn't stay idle for long.
+ * (plus, avoids some kind of re-activation race.)
+ */
+ if (list_empty(&qh->qtd_list)) {
+ if (qh->stamp == oxu->stamp)
+ action = TIMER_ASYNC_SHRINK;
+ else if (!oxu->reclaim
+ && qh->qh_state == QH_STATE_LINKED)
+ start_unlink_async(oxu, qh);
+ }
+
+ qh = qh->qh_next.qh;
+ } while (qh);
+ }
+ if (action == TIMER_ASYNC_SHRINK)
+ timer_action(oxu, TIMER_ASYNC_SHRINK);
+}
+
+/*
+ * periodic_next_shadow - return "next" pointer on shadow list
+ * @periodic: host pointer to qh/itd/sitd
+ * @tag: hardware tag for type of this record
+ */
+static union ehci_shadow *periodic_next_shadow(union ehci_shadow *periodic,
+ __le32 tag)
+{
+ switch (tag) {
+ default:
+ case Q_TYPE_QH:
+ return &periodic->qh->qh_next;
+ }
+}
+
+/* caller must hold oxu->lock */
+static void periodic_unlink(struct oxu_hcd *oxu, unsigned frame, void *ptr)
+{
+ union ehci_shadow *prev_p = &oxu->pshadow[frame];
+ __le32 *hw_p = &oxu->periodic[frame];
+ union ehci_shadow here = *prev_p;
+
+ /* find predecessor of "ptr"; hw and shadow lists are in sync */
+ while (here.ptr && here.ptr != ptr) {
+ prev_p = periodic_next_shadow(prev_p, Q_NEXT_TYPE(*hw_p));
+ hw_p = here.hw_next;
+ here = *prev_p;
+ }
+ /* an interrupt entry (at list end) could have been shared */
+ if (!here.ptr)
+ return;
+
+ /* update shadow and hardware lists ... the old "next" pointers
+ * from ptr may still be in use, the caller updates them.
+ */
+ *prev_p = *periodic_next_shadow(&here, Q_NEXT_TYPE(*hw_p));
+ *hw_p = *here.hw_next;
+}
+
+/* how many of the uframe's 125 usecs are allocated? */
+static unsigned short periodic_usecs(struct oxu_hcd *oxu,
+ unsigned frame, unsigned uframe)
+{
+ __le32 *hw_p = &oxu->periodic[frame];
+ union ehci_shadow *q = &oxu->pshadow[frame];
+ unsigned usecs = 0;
+
+ while (q->ptr) {
+ switch (Q_NEXT_TYPE(*hw_p)) {
+ case Q_TYPE_QH:
+ default:
+ /* is it in the S-mask? */
+ if (q->qh->hw_info2 & cpu_to_le32(1 << uframe))
+ usecs += q->qh->usecs;
+ /* ... or C-mask? */
+ if (q->qh->hw_info2 & cpu_to_le32(1 << (8 + uframe)))
+ usecs += q->qh->c_usecs;
+ hw_p = &q->qh->hw_next;
+ q = &q->qh->qh_next;
+ break;
+ }
+ }
+#ifdef DEBUG
+ if (usecs > 100)
+ oxu_err(oxu, "uframe %d sched overrun: %d usecs\n",
+ frame * 8 + uframe, usecs);
+#endif
+ return usecs;
+}
+
+static int enable_periodic(struct oxu_hcd *oxu)
+{
+ u32 cmd;
+ int status;
+
+ /* did clearing PSE did take effect yet?
+ * takes effect only at frame boundaries...
+ */
+ status = handshake(oxu, &oxu->regs->status, STS_PSS, 0, 9 * 125);
+ if (status != 0) {
+ oxu_to_hcd(oxu)->state = HC_STATE_HALT;
+ return status;
+ }
+
+ cmd = readl(&oxu->regs->command) | CMD_PSE;
+ writel(cmd, &oxu->regs->command);
+ /* posted write ... PSS happens later */
+ oxu_to_hcd(oxu)->state = HC_STATE_RUNNING;
+
+ /* make sure ehci_work scans these */
+ oxu->next_uframe = readl(&oxu->regs->frame_index)
+ % (oxu->periodic_size << 3);
+ return 0;
+}
+
+static int disable_periodic(struct oxu_hcd *oxu)
+{
+ u32 cmd;
+ int status;
+
+ /* did setting PSE not take effect yet?
+ * takes effect only at frame boundaries...
+ */
+ status = handshake(oxu, &oxu->regs->status, STS_PSS, STS_PSS, 9 * 125);
+ if (status != 0) {
+ oxu_to_hcd(oxu)->state = HC_STATE_HALT;
+ return status;
+ }
+
+ cmd = readl(&oxu->regs->command) & ~CMD_PSE;
+ writel(cmd, &oxu->regs->command);
+ /* posted write ... */
+
+ oxu->next_uframe = -1;
+ return 0;
+}
+
+/* periodic schedule slots have iso tds (normal or split) first, then a
+ * sparse tree for active interrupt transfers.
+ *
+ * this just links in a qh; caller guarantees uframe masks are set right.
+ * no FSTN support (yet; oxu 0.96+)
+ */
+static int qh_link_periodic(struct oxu_hcd *oxu, struct ehci_qh *qh)
+{
+ unsigned i;
+ unsigned period = qh->period;
+
+ dev_dbg(&qh->dev->dev,
+ "link qh%d-%04x/%p start %d [%d/%d us]\n",
+ period, le32_to_cpup(&qh->hw_info2) & (QH_CMASK | QH_SMASK),
+ qh, qh->start, qh->usecs, qh->c_usecs);
+
+ /* high bandwidth, or otherwise every microframe */
+ if (period == 0)
+ period = 1;
+
+ for (i = qh->start; i < oxu->periodic_size; i += period) {
+ union ehci_shadow *prev = &oxu->pshadow[i];
+ __le32 *hw_p = &oxu->periodic[i];
+ union ehci_shadow here = *prev;
+ __le32 type = 0;
+
+ /* skip the iso nodes at list head */
+ while (here.ptr) {
+ type = Q_NEXT_TYPE(*hw_p);
+ if (type == Q_TYPE_QH)
+ break;
+ prev = periodic_next_shadow(prev, type);
+ hw_p = &here.qh->hw_next;
+ here = *prev;
+ }
+
+ /* sorting each branch by period (slow-->fast)
+ * enables sharing interior tree nodes
+ */
+ while (here.ptr && qh != here.qh) {
+ if (qh->period > here.qh->period)
+ break;
+ prev = &here.qh->qh_next;
+ hw_p = &here.qh->hw_next;
+ here = *prev;
+ }
+ /* link in this qh, unless some earlier pass did that */
+ if (qh != here.qh) {
+ qh->qh_next = here;
+ if (here.qh)
+ qh->hw_next = *hw_p;
+ wmb();
+ prev->qh = qh;
+ *hw_p = QH_NEXT(qh->qh_dma);
+ }
+ }
+ qh->qh_state = QH_STATE_LINKED;
+ qh_get(qh);
+
+ /* update per-qh bandwidth for usbfs */
+ oxu_to_hcd(oxu)->self.bandwidth_allocated += qh->period
+ ? ((qh->usecs + qh->c_usecs) / qh->period)
+ : (qh->usecs * 8);
+
+ /* maybe enable periodic schedule processing */
+ if (!oxu->periodic_sched++)
+ return enable_periodic(oxu);
+
+ return 0;
+}
+
+static void qh_unlink_periodic(struct oxu_hcd *oxu, struct ehci_qh *qh)
+{
+ unsigned i;
+ unsigned period;
+
+ /* FIXME:
+ * IF this isn't high speed
+ * and this qh is active in the current uframe
+ * (and overlay token SplitXstate is false?)
+ * THEN
+ * qh->hw_info1 |= __constant_cpu_to_le32(1 << 7 "ignore");
+ */
+
+ /* high bandwidth, or otherwise part of every microframe */
+ period = qh->period;
+ if (period == 0)
+ period = 1;
+
+ for (i = qh->start; i < oxu->periodic_size; i += period)
+ periodic_unlink(oxu, i, qh);
+
+ /* update per-qh bandwidth for usbfs */
+ oxu_to_hcd(oxu)->self.bandwidth_allocated -= qh->period
+ ? ((qh->usecs + qh->c_usecs) / qh->period)
+ : (qh->usecs * 8);
+
+ dev_dbg(&qh->dev->dev,
+ "unlink qh%d-%04x/%p start %d [%d/%d us]\n",
+ qh->period,
+ le32_to_cpup(&qh->hw_info2) & (QH_CMASK | QH_SMASK),
+ qh, qh->start, qh->usecs, qh->c_usecs);
+
+ /* qh->qh_next still "live" to HC */
+ qh->qh_state = QH_STATE_UNLINK;
+ qh->qh_next.ptr = NULL;
+ qh_put(qh);
+
+ /* maybe turn off periodic schedule */
+ oxu->periodic_sched--;
+ if (!oxu->periodic_sched)
+ (void) disable_periodic(oxu);
+}
+
+static void intr_deschedule(struct oxu_hcd *oxu, struct ehci_qh *qh)
+{
+ unsigned wait;
+
+ qh_unlink_periodic(oxu, qh);
+
+ /* simple/paranoid: always delay, expecting the HC needs to read
+ * qh->hw_next or finish a writeback after SPLIT/CSPLIT ... and
+ * expect khubd to clean up after any CSPLITs we won't issue.
+ * active high speed queues may need bigger delays...
+ */
+ if (list_empty(&qh->qtd_list)
+ || (__constant_cpu_to_le32(QH_CMASK) & qh->hw_info2) != 0)
+ wait = 2;
+ else
+ wait = 55; /* worst case: 3 * 1024 */
+
+ udelay(wait);
+ qh->qh_state = QH_STATE_IDLE;
+ qh->hw_next = EHCI_LIST_END;
+ wmb();
+}
+
+static int check_period(struct oxu_hcd *oxu,
+ unsigned frame, unsigned uframe,
+ unsigned period, unsigned usecs)
+{
+ int claimed;
+
+ /* complete split running into next frame?
+ * given FSTN support, we could sometimes check...
+ */
+ if (uframe >= 8)
+ return 0;
+
+ /*
+ * 80% periodic == 100 usec/uframe available
+ * convert "usecs we need" to "max already claimed"
+ */
+ usecs = 100 - usecs;
+
+ /* we "know" 2 and 4 uframe intervals were rejected; so
+ * for period 0, check _every_ microframe in the schedule.
+ */
+ if (unlikely(period == 0)) {
+ do {
+ for (uframe = 0; uframe < 7; uframe++) {
+ claimed = periodic_usecs(oxu, frame, uframe);
+ if (claimed > usecs)
+ return 0;
+ }
+ } while ((frame += 1) < oxu->periodic_size);
+
+ /* just check the specified uframe, at that period */
+ } else {
+ do {
+ claimed = periodic_usecs(oxu, frame, uframe);
+ if (claimed > usecs)
+ return 0;
+ } while ((frame += period) < oxu->periodic_size);
+ }
+
+ return 1;
+}
+
+static int check_intr_schedule(struct oxu_hcd *oxu,
+ unsigned frame, unsigned uframe,
+ const struct ehci_qh *qh, __le32 *c_maskp)
+{
+ int retval = -ENOSPC;
+
+ if (qh->c_usecs && uframe >= 6) /* FSTN territory? */
+ goto done;
+
+ if (!check_period(oxu, frame, uframe, qh->period, qh->usecs))
+ goto done;
+ if (!qh->c_usecs) {
+ retval = 0;
+ *c_maskp = 0;
+ goto done;
+ }
+
+done:
+ return retval;
+}
+
+/* "first fit" scheduling policy used the first time through,
+ * or when the previous schedule slot can't be re-used.
+ */
+static int qh_schedule(struct oxu_hcd *oxu, struct ehci_qh *qh)
+{
+ int status;
+ unsigned uframe;
+ __le32 c_mask;
+ unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
+
+ qh_refresh(oxu, qh);
+ qh->hw_next = EHCI_LIST_END;
+ frame = qh->start;
+
+ /* reuse the previous schedule slots, if we can */
+ if (frame < qh->period) {
+ uframe = ffs(le32_to_cpup(&qh->hw_info2) & QH_SMASK);
+ status = check_intr_schedule(oxu, frame, --uframe,
+ qh, &c_mask);
+ } else {
+ uframe = 0;
+ c_mask = 0;
+ status = -ENOSPC;
+ }
+
+ /* else scan the schedule to find a group of slots such that all
+ * uframes have enough periodic bandwidth available.
+ */
+ if (status) {
+ /* "normal" case, uframing flexible except with splits */
+ if (qh->period) {
+ frame = qh->period - 1;
+ do {
+ for (uframe = 0; uframe < 8; uframe++) {
+ status = check_intr_schedule(oxu,
+ frame, uframe, qh,
+ &c_mask);
+ if (status == 0)
+ break;
+ }
+ } while (status && frame--);
+
+ /* qh->period == 0 means every uframe */
+ } else {
+ frame = 0;
+ status = check_intr_schedule(oxu, 0, 0, qh, &c_mask);
+ }
+ if (status)
+ goto done;
+ qh->start = frame;
+
+ /* reset S-frame and (maybe) C-frame masks */
+ qh->hw_info2 &= __constant_cpu_to_le32(~(QH_CMASK | QH_SMASK));
+ qh->hw_info2 |= qh->period
+ ? cpu_to_le32(1 << uframe)
+ : __constant_cpu_to_le32(QH_SMASK);
+ qh->hw_info2 |= c_mask;
+ } else
+ oxu_dbg(oxu, "reused qh %p schedule\n", qh);
+
+ /* stuff into the periodic schedule */
+ status = qh_link_periodic(oxu, qh);
+done:
+ return status;
+}
+
+static int intr_submit(struct oxu_hcd *oxu, struct urb *urb,
+ struct list_head *qtd_list, gfp_t mem_flags)
+{
+ unsigned epnum;
+ unsigned long flags;
+ struct ehci_qh *qh;
+ int status = 0;
+ struct list_head empty;
+
+ /* get endpoint and transfer/schedule data */
+ epnum = urb->ep->desc.bEndpointAddress;
+
+ spin_lock_irqsave(&oxu->lock, flags);
+
+ if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
+ &oxu_to_hcd(oxu)->flags))) {
+ status = -ESHUTDOWN;
+ goto done;
+ }
+
+ /* get qh and force any scheduling errors */
+ INIT_LIST_HEAD(&empty);
+ qh = qh_append_tds(oxu, urb, &empty, epnum, &urb->ep->hcpriv);
+ if (qh == NULL) {
+ status = -ENOMEM;
+ goto done;
+ }
+ if (qh->qh_state == QH_STATE_IDLE) {
+ status = qh_schedule(oxu, qh);
+ if (status != 0)
+ goto done;
+ }
+
+ /* then queue the urb's tds to the qh */
+ qh = qh_append_tds(oxu, urb, qtd_list, epnum, &urb->ep->hcpriv);
+ BUG_ON(qh == NULL);
+
+ /* ... update usbfs periodic stats */
+ oxu_to_hcd(oxu)->self.bandwidth_int_reqs++;
+
+done:
+ spin_unlock_irqrestore(&oxu->lock, flags);
+ if (status)
+ qtd_list_free(oxu, urb, qtd_list);
+
+ return status;
+}
+
+static inline int itd_submit(struct oxu_hcd *oxu, struct urb *urb,
+ gfp_t mem_flags)
+{
+ oxu_dbg(oxu, "iso support is missing!\n");
+ return -ENOSYS;
+}
+
+static inline int sitd_submit(struct oxu_hcd *oxu, struct urb *urb,
+ gfp_t mem_flags)
+{
+ oxu_dbg(oxu, "split iso support is missing!\n");
+ return -ENOSYS;
+}
+
+static void scan_periodic(struct oxu_hcd *oxu)
+{
+ unsigned frame, clock, now_uframe, mod;
+ unsigned modified;
+
+ mod = oxu->periodic_size << 3;
+
+ /*
+ * When running, scan from last scan point up to "now"
+ * else clean up by scanning everything that's left.
+ * Touches as few pages as possible: cache-friendly.
+ */
+ now_uframe = oxu->next_uframe;
+ if (HC_IS_RUNNING(oxu_to_hcd(oxu)->state))
+ clock = readl(&oxu->regs->frame_index);
+ else
+ clock = now_uframe + mod - 1;
+ clock %= mod;
+
+ for (;;) {
+ union ehci_shadow q, *q_p;
+ __le32 type, *hw_p;
+ unsigned uframes;
+
+ /* don't scan past the live uframe */
+ frame = now_uframe >> 3;
+ if (frame == (clock >> 3))
+ uframes = now_uframe & 0x07;
+ else {
+ /* safe to scan the whole frame at once */
+ now_uframe |= 0x07;
+ uframes = 8;
+ }
+
+restart:
+ /* scan each element in frame's queue for completions */
+ q_p = &oxu->pshadow[frame];
+ hw_p = &oxu->periodic[frame];
+ q.ptr = q_p->ptr;
+ type = Q_NEXT_TYPE(*hw_p);
+ modified = 0;
+
+ while (q.ptr != NULL) {
+ union ehci_shadow temp;
+ int live;
+
+ live = HC_IS_RUNNING(oxu_to_hcd(oxu)->state);
+ switch (type) {
+ case Q_TYPE_QH:
+ /* handle any completions */
+ temp.qh = qh_get(q.qh);
+ type = Q_NEXT_TYPE(q.qh->hw_next);
+ q = q.qh->qh_next;
+ modified = qh_completions(oxu, temp.qh);
+ if (unlikely(list_empty(&temp.qh->qtd_list)))
+ intr_deschedule(oxu, temp.qh);
+ qh_put(temp.qh);
+ break;
+ default:
+ dbg("corrupt type %d frame %d shadow %p",
+ type, frame, q.ptr);
+ q.ptr = NULL;
+ }
+
+ /* assume completion callbacks modify the queue */
+ if (unlikely(modified))
+ goto restart;
+ }
+
+ /* Stop when we catch up to the HC */
+
+ /* FIXME: this assumes we won't get lapped when
+ * latencies climb; that should be rare, but...
+ * detect it, and just go all the way around.
+ * FLR might help detect this case, so long as latencies
+ * don't exceed periodic_size msec (default 1.024 sec).
+ */
+
+ /* FIXME: likewise assumes HC doesn't halt mid-scan */
+
+ if (now_uframe == clock) {
+ unsigned now;
+
+ if (!HC_IS_RUNNING(oxu_to_hcd(oxu)->state))
+ break;
+ oxu->next_uframe = now_uframe;
+ now = readl(&oxu->regs->frame_index) % mod;
+ if (now_uframe == now)
+ break;
+
+ /* rescan the rest of this frame, then ... */
+ clock = now;
+ } else {
+ now_uframe++;
+ now_uframe %= mod;
+ }
+ }
+}
+
+/* On some systems, leaving remote wakeup enabled prevents system shutdown.
+ * The firmware seems to think that powering off is a wakeup event!
+ * This routine turns off remote wakeup and everything else, on all ports.
+ */
+static void ehci_turn_off_all_ports(struct oxu_hcd *oxu)
+{
+ int port = HCS_N_PORTS(oxu->hcs_params);
+
+ while (port--)
+ writel(PORT_RWC_BITS, &oxu->regs->port_status[port]);
+}
+
+static void ehci_port_power(struct oxu_hcd *oxu, int is_on)
+{
+ unsigned port;
+
+ if (!HCS_PPC(oxu->hcs_params))
+ return;
+
+ oxu_dbg(oxu, "...power%s ports...\n", is_on ? "up" : "down");
+ for (port = HCS_N_PORTS(oxu->hcs_params); port > 0; )
+ (void) oxu_hub_control(oxu_to_hcd(oxu),
+ is_on ? SetPortFeature : ClearPortFeature,
+ USB_PORT_FEAT_POWER,
+ port--, NULL, 0);
+ msleep(20);
+}
+
+/* Called from some interrupts, timers, and so on.
+ * It calls driver completion functions, after dropping oxu->lock.
+ */
+static void ehci_work(struct oxu_hcd *oxu)
+{
+ timer_action_done(oxu, TIMER_IO_WATCHDOG);
+ if (oxu->reclaim_ready)
+ end_unlink_async(oxu);
+
+ /* another CPU may drop oxu->lock during a schedule scan while
+ * it reports urb completions. this flag guards against bogus
+ * attempts at re-entrant schedule scanning.
+ */
+ if (oxu->scanning)
+ return;
+ oxu->scanning = 1;
+ scan_async(oxu);
+ if (oxu->next_uframe != -1)
+ scan_periodic(oxu);
+ oxu->scanning = 0;
+
+ /* the IO watchdog guards against hardware or driver bugs that
+ * misplace IRQs, and should let us run completely without IRQs.
+ * such lossage has been observed on both VT6202 and VT8235.
+ */
+ if (HC_IS_RUNNING(oxu_to_hcd(oxu)->state) &&
+ (oxu->async->qh_next.ptr != NULL ||
+ oxu->periodic_sched != 0))
+ timer_action(oxu, TIMER_IO_WATCHDOG);
+}
+
+static void unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh)
+{
+ /* if we need to use IAA and it's busy, defer */
+ if (qh->qh_state == QH_STATE_LINKED
+ && oxu->reclaim
+ && HC_IS_RUNNING(oxu_to_hcd(oxu)->state)) {
+ struct ehci_qh *last;
+
+ for (last = oxu->reclaim;
+ last->reclaim;
+ last = last->reclaim)
+ continue;
+ qh->qh_state = QH_STATE_UNLINK_WAIT;
+ last->reclaim = qh;
+
+ /* bypass IAA if the hc can't care */
+ } else if (!HC_IS_RUNNING(oxu_to_hcd(oxu)->state) && oxu->reclaim)
+ end_unlink_async(oxu);
+
+ /* something else might have unlinked the qh by now */
+ if (qh->qh_state == QH_STATE_LINKED)
+ start_unlink_async(oxu, qh);
+}
+
+/*
+ * USB host controller methods
+ */
+
+static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+ u32 status, pcd_status = 0;
+ int bh;
+
+ spin_lock(&oxu->lock);
+
+ status = readl(&oxu->regs->status);
+
+ /* e.g. cardbus physical eject */
+ if (status == ~(u32) 0) {
+ oxu_dbg(oxu, "device removed\n");
+ goto dead;
+ }
+
+ status &= INTR_MASK;
+ if (!status) { /* irq sharing? */
+ spin_unlock(&oxu->lock);
+ return IRQ_NONE;
+ }
+
+ /* clear (just) interrupts */
+ writel(status, &oxu->regs->status);
+ readl(&oxu->regs->command); /* unblock posted write */
+ bh = 0;
+
+#ifdef OXU_VERBOSE_DEBUG
+ /* unrequested/ignored: Frame List Rollover */
+ dbg_status(oxu, "irq", status);
+#endif
+
+ /* INT, ERR, and IAA interrupt rates can be throttled */
+
+ /* normal [4.15.1.2] or error [4.15.1.1] completion */
+ if (likely((status & (STS_INT|STS_ERR)) != 0))
+ bh = 1;
+
+ /* complete the unlinking of some qh [4.15.2.3] */
+ if (status & STS_IAA) {
+ oxu->reclaim_ready = 1;
+ bh = 1;
+ }
+
+ /* remote wakeup [4.3.1] */
+ if (status & STS_PCD) {
+ unsigned i = HCS_N_PORTS(oxu->hcs_params);
+ pcd_status = status;
+
+ /* resume root hub? */
+ if (!(readl(&oxu->regs->command) & CMD_RUN))
+ usb_hcd_resume_root_hub(hcd);
+
+ while (i--) {
+ int pstatus = readl(&oxu->regs->port_status[i]);
+
+ if (pstatus & PORT_OWNER)
+ continue;
+ if (!(pstatus & PORT_RESUME)
+ || oxu->reset_done[i] != 0)
+ continue;
+
+ /* start 20 msec resume signaling from this port,
+ * and make khubd collect PORT_STAT_C_SUSPEND to
+ * stop that signaling.
+ */
+ oxu->reset_done[i] = jiffies + msecs_to_jiffies(20);
+ oxu_dbg(oxu, "port %d remote wakeup\n", i + 1);
+ mod_timer(&hcd->rh_timer, oxu->reset_done[i]);
+ }
+ }
+
+ /* PCI errors [4.15.2.4] */
+ if (unlikely((status & STS_FATAL) != 0)) {
+ /* bogus "fatal" IRQs appear on some chips... why? */
+ status = readl(&oxu->regs->status);
+ dbg_cmd(oxu, "fatal", readl(&oxu->regs->command));
+ dbg_status(oxu, "fatal", status);
+ if (status & STS_HALT) {
+ oxu_err(oxu, "fatal error\n");
+dead:
+ ehci_reset(oxu);
+ writel(0, &oxu->regs->configured_flag);
+ /* generic layer kills/unlinks all urbs, then
+ * uses oxu_stop to clean up the rest
+ */
+ bh = 1;
+ }
+ }
+
+ if (bh)
+ ehci_work(oxu);
+ spin_unlock(&oxu->lock);
+ if (pcd_status & STS_PCD)
+ usb_hcd_poll_rh_status(hcd);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t oxu_irq(struct usb_hcd *hcd)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+ int ret = IRQ_HANDLED;
+
+ u32 status = oxu_readl(hcd->regs, OXU_CHIPIRQSTATUS);
+ u32 enable = oxu_readl(hcd->regs, OXU_CHIPIRQEN_SET);
+
+ /* Disable all interrupt */
+ oxu_writel(hcd->regs, OXU_CHIPIRQEN_CLR, enable);
+
+ if ((oxu->is_otg && (status & OXU_USBOTGI)) ||
+ (!oxu->is_otg && (status & OXU_USBSPHI)))
+ oxu210_hcd_irq(hcd);
+ else
+ ret = IRQ_NONE;
+
+ /* Enable all interrupt back */
+ oxu_writel(hcd->regs, OXU_CHIPIRQEN_SET, enable);
+
+ return ret;
+}
+
+static void oxu_watchdog(unsigned long param)
+{
+ struct oxu_hcd *oxu = (struct oxu_hcd *) param;
+ unsigned long flags;
+
+ spin_lock_irqsave(&oxu->lock, flags);
+
+ /* lost IAA irqs wedge things badly; seen with a vt8235 */
+ if (oxu->reclaim) {
+ u32 status = readl(&oxu->regs->status);
+ if (status & STS_IAA) {
+ oxu_vdbg(oxu, "lost IAA\n");
+ writel(STS_IAA, &oxu->regs->status);
+ oxu->reclaim_ready = 1;
+ }
+ }
+
+ /* stop async processing after it's idled a bit */
+ if (test_bit(TIMER_ASYNC_OFF, &oxu->actions))
+ start_unlink_async(oxu, oxu->async);
+
+ /* oxu could run by timer, without IRQs ... */
+ ehci_work(oxu);
+
+ spin_unlock_irqrestore(&oxu->lock, flags);
+}
+
+/* One-time init, only for memory state.
+ */
+static int oxu_hcd_init(struct usb_hcd *hcd)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+ u32 temp;
+ int retval;
+ u32 hcc_params;
+
+ spin_lock_init(&oxu->lock);
+
+ init_timer(&oxu->watchdog);
+ oxu->watchdog.function = oxu_watchdog;
+ oxu->watchdog.data = (unsigned long) oxu;
+
+ /*
+ * hw default: 1K periodic list heads, one per frame.
+ * periodic_size can shrink by USBCMD update if hcc_params allows.
+ */
+ oxu->periodic_size = DEFAULT_I_TDPS;
+ retval = ehci_mem_init(oxu, GFP_KERNEL);
+ if (retval < 0)
+ return retval;
+
+ /* controllers may cache some of the periodic schedule ... */
+ hcc_params = readl(&oxu->caps->hcc_params);
+ if (HCC_ISOC_CACHE(hcc_params)) /* full frame cache */
+ oxu->i_thresh = 8;
+ else /* N microframes cached */
+ oxu->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
+
+ oxu->reclaim = NULL;
+ oxu->reclaim_ready = 0;
+ oxu->next_uframe = -1;
+
+ /*
+ * dedicate a qh for the async ring head, since we couldn't unlink
+ * a 'real' qh without stopping the async schedule [4.8]. use it
+ * as the 'reclamation list head' too.
+ * its dummy is used in hw_alt_next of many tds, to prevent the qh
+ * from automatically advancing to the next td after short reads.
+ */
+ oxu->async->qh_next.qh = NULL;
+ oxu->async->hw_next = QH_NEXT(oxu->async->qh_dma);
+ oxu->async->hw_info1 = cpu_to_le32(QH_HEAD);
+ oxu->async->hw_token = cpu_to_le32(QTD_STS_HALT);
+ oxu->async->hw_qtd_next = EHCI_LIST_END;
+ oxu->async->qh_state = QH_STATE_LINKED;
+ oxu->async->hw_alt_next = QTD_NEXT(oxu->async->dummy->qtd_dma);
+
+ /* clear interrupt enables, set irq latency */
+ if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
+ log2_irq_thresh = 0;
+ temp = 1 << (16 + log2_irq_thresh);
+ if (HCC_CANPARK(hcc_params)) {
+ /* HW default park == 3, on hardware that supports it (like
+ * NVidia and ALI silicon), maximizes throughput on the async
+ * schedule by avoiding QH fetches between transfers.
+ *
+ * With fast usb storage devices and NForce2, "park" seems to
+ * make problems: throughput reduction (!), data errors...
+ */
+ if (park) {
+ park = min(park, (unsigned) 3);
+ temp |= CMD_PARK;
+ temp |= park << 8;
+ }
+ oxu_dbg(oxu, "park %d\n", park);
+ }
+ if (HCC_PGM_FRAMELISTLEN(hcc_params)) {
+ /* periodic schedule size can be smaller than default */
+ temp &= ~(3 << 2);
+ temp |= (EHCI_TUNE_FLS << 2);
+ }
+ oxu->command = temp;
+
+ return 0;
+}
+
+/* Called during probe() after chip reset completes.
+ */
+static int oxu_reset(struct usb_hcd *hcd)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+ int ret;
+
+ spin_lock_init(&oxu->mem_lock);
+ INIT_LIST_HEAD(&oxu->urb_list);
+ oxu->urb_len = 0;
+
+ /* FIMXE */
+ hcd->self.controller->dma_mask = 0UL;
+
+ if (oxu->is_otg) {
+ oxu->caps = hcd->regs + OXU_OTG_CAP_OFFSET;
+ oxu->regs = hcd->regs + OXU_OTG_CAP_OFFSET + \
+ HC_LENGTH(readl(&oxu->caps->hc_capbase));
+
+ oxu->mem = hcd->regs + OXU_SPH_MEM;
+ } else {
+ oxu->caps = hcd->regs + OXU_SPH_CAP_OFFSET;
+ oxu->regs = hcd->regs + OXU_SPH_CAP_OFFSET + \
+ HC_LENGTH(readl(&oxu->caps->hc_capbase));
+
+ oxu->mem = hcd->regs + OXU_OTG_MEM;
+ }
+
+ oxu->hcs_params = readl(&oxu->caps->hcs_params);
+ oxu->sbrn = 0x20;
+
+ ret = oxu_hcd_init(hcd);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int oxu_run(struct usb_hcd *hcd)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+ int retval;
+ u32 temp, hcc_params;
+
+ hcd->uses_new_polling = 1;
+ hcd->poll_rh = 0;
+
+ /* EHCI spec section 4.1 */
+ retval = ehci_reset(oxu);
+ if (retval != 0) {
+ ehci_mem_cleanup(oxu);
+ return retval;
+ }
+ writel(oxu->periodic_dma, &oxu->regs->frame_list);
+ writel((u32) oxu->async->qh_dma, &oxu->regs->async_next);
+
+ /* hcc_params controls whether oxu->regs->segment must (!!!)
+ * be used; it constrains QH/ITD/SITD and QTD locations.
+ * pci_pool consistent memory always uses segment zero.
+ * streaming mappings for I/O buffers, like pci_map_single(),
+ * can return segments above 4GB, if the device allows.
+ *
+ * NOTE: the dma mask is visible through dma_supported(), so
+ * drivers can pass this info along ... like NETIF_F_HIGHDMA,
+ * Scsi_Host.highmem_io, and so forth. It's readonly to all
+ * host side drivers though.
+ */
+ hcc_params = readl(&oxu->caps->hcc_params);
+ if (HCC_64BIT_ADDR(hcc_params))
+ writel(0, &oxu->regs->segment);
+
+ oxu->command &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE |
+ CMD_ASE | CMD_RESET);
+ oxu->command |= CMD_RUN;
+ writel(oxu->command, &oxu->regs->command);
+ dbg_cmd(oxu, "init", oxu->command);
+
+ /*
+ * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
+ * are explicitly handed to companion controller(s), so no TT is
+ * involved with the root hub. (Except where one is integrated,
+ * and there's no companion controller unless maybe for USB OTG.)
+ */
+ hcd->state = HC_STATE_RUNNING;
+ writel(FLAG_CF, &oxu->regs->configured_flag);
+ readl(&oxu->regs->command); /* unblock posted writes */
+
+ temp = HC_VERSION(readl(&oxu->caps->hc_capbase));
+ oxu_info(oxu, "USB %x.%x started, quasi-EHCI %x.%02x, driver %s%s\n",
+ ((oxu->sbrn & 0xf0)>>4), (oxu->sbrn & 0x0f),
+ temp >> 8, temp & 0xff, DRIVER_VERSION,
+ ignore_oc ? ", overcurrent ignored" : "");
+
+ writel(INTR_MASK, &oxu->regs->intr_enable); /* Turn On Interrupts */
+
+ return 0;
+}
+
+static void oxu_stop(struct usb_hcd *hcd)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+
+ /* Turn off port power on all root hub ports. */
+ ehci_port_power(oxu, 0);
+
+ /* no more interrupts ... */
+ del_timer_sync(&oxu->watchdog);
+
+ spin_lock_irq(&oxu->lock);
+ if (HC_IS_RUNNING(hcd->state))
+ ehci_quiesce(oxu);
+
+ ehci_reset(oxu);
+ writel(0, &oxu->regs->intr_enable);
+ spin_unlock_irq(&oxu->lock);
+
+ /* let companion controllers work when we aren't */
+ writel(0, &oxu->regs->configured_flag);
+
+ /* root hub is shut down separately (first, when possible) */
+ spin_lock_irq(&oxu->lock);
+ if (oxu->async)
+ ehci_work(oxu);
+ spin_unlock_irq(&oxu->lock);
+ ehci_mem_cleanup(oxu);
+
+ dbg_status(oxu, "oxu_stop completed", readl(&oxu->regs->status));
+}
+
+/* Kick in for silicon on any bus (not just pci, etc).
+ * This forcibly disables dma and IRQs, helping kexec and other cases
+ * where the next system software may expect clean state.
+ */
+static void oxu_shutdown(struct usb_hcd *hcd)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+
+ (void) ehci_halt(oxu);
+ ehci_turn_off_all_ports(oxu);
+
+ /* make BIOS/etc use companion controller during reboot */
+ writel(0, &oxu->regs->configured_flag);
+
+ /* unblock posted writes */
+ readl(&oxu->regs->configured_flag);
+}
+
+/* Non-error returns are a promise to giveback() the urb later
+ * we drop ownership so next owner (or urb unlink) can get it
+ *
+ * urb + dev is in hcd.self.controller.urb_list
+ * we're queueing TDs onto software and hardware lists
+ *
+ * hcd-specific init for hcpriv hasn't been done yet
+ *
+ * NOTE: control, bulk, and interrupt share the same code to append TDs
+ * to a (possibly active) QH, and the same QH scanning code.
+ */
+static int __oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+ struct list_head qtd_list;
+
+ INIT_LIST_HEAD(&qtd_list);
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ default:
+ if (!qh_urb_transaction(oxu, urb, &qtd_list, mem_flags))
+ return -ENOMEM;
+ return submit_async(oxu, urb, &qtd_list, mem_flags);
+
+ case PIPE_INTERRUPT:
+ if (!qh_urb_transaction(oxu, urb, &qtd_list, mem_flags))
+ return -ENOMEM;
+ return intr_submit(oxu, urb, &qtd_list, mem_flags);
+
+ case PIPE_ISOCHRONOUS:
+ if (urb->dev->speed == USB_SPEED_HIGH)
+ return itd_submit(oxu, urb, mem_flags);
+ else
+ return sitd_submit(oxu, urb, mem_flags);
+ }
+}
+
+/* This function is responsible for breaking URBs with big data size
+ * into smaller size and processing small urbs in sequence.
+ */
+static int oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+ int num, rem;
+ int transfer_buffer_length;
+ void *transfer_buffer;
+ struct urb *murb;
+ int i, ret;
+
+ /* If not bulk pipe just enqueue the URB */
+ if (!usb_pipebulk(urb->pipe))
+ return __oxu_urb_enqueue(hcd, urb, mem_flags);
+
+ /* Otherwise we should verify the USB transfer buffer size! */
+ transfer_buffer = urb->transfer_buffer;
+ transfer_buffer_length = urb->transfer_buffer_length;
+
+ num = urb->transfer_buffer_length / 4096;
+ rem = urb->transfer_buffer_length % 4096;
+ if (rem != 0)
+ num++;
+
+ /* If URB is smaller than 4096 bytes just enqueue it! */
+ if (num == 1)
+ return __oxu_urb_enqueue(hcd, urb, mem_flags);
+
+ /* Ok, we have more job to do! :) */
+
+ for (i = 0; i < num - 1; i++) {
+ /* Get free micro URB poll till a free urb is recieved */
+
+ do {
+ murb = (struct urb *) oxu_murb_alloc(oxu);
+ if (!murb)
+ schedule();
+ } while (!murb);
+
+ /* Coping the urb */
+ memcpy(murb, urb, sizeof(struct urb));
+
+ murb->transfer_buffer_length = 4096;
+ murb->transfer_buffer = transfer_buffer + i * 4096;
+
+ /* Null pointer for the encodes that this is a micro urb */
+ murb->complete = NULL;
+
+ ((struct oxu_murb *) murb)->main = urb;
+ ((struct oxu_murb *) murb)->last = 0;
+
+ /* This loop is to guarantee urb to be processed when there's
+ * not enough resources at a particular time by retrying.
+ */
+ do {
+ ret = __oxu_urb_enqueue(hcd, murb, mem_flags);
+ if (ret)
+ schedule();
+ } while (ret);
+ }
+
+ /* Last urb requires special handling */
+
+ /* Get free micro URB poll till a free urb is recieved */
+ do {
+ murb = (struct urb *) oxu_murb_alloc(oxu);
+ if (!murb)
+ schedule();
+ } while (!murb);
+
+ /* Coping the urb */
+ memcpy(murb, urb, sizeof(struct urb));
+
+ murb->transfer_buffer_length = rem > 0 ? rem : 4096;
+ murb->transfer_buffer = transfer_buffer + (num - 1) * 4096;
+
+ /* Null pointer for the encodes that this is a micro urb */
+ murb->complete = NULL;
+
+ ((struct oxu_murb *) murb)->main = urb;
+ ((struct oxu_murb *) murb)->last = 1;
+
+ do {
+ ret = __oxu_urb_enqueue(hcd, murb, mem_flags);
+ if (ret)
+ schedule();
+ } while (ret);
+
+ return ret;
+}
+
+/* Remove from hardware lists.
+ * Completions normally happen asynchronously
+ */
+static int oxu_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+ struct ehci_qh *qh;
+ unsigned long flags;
+
+ spin_lock_irqsave(&oxu->lock, flags);
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ default:
+ qh = (struct ehci_qh *) urb->hcpriv;
+ if (!qh)
+ break;
+ unlink_async(oxu, qh);
+ break;
+
+ case PIPE_INTERRUPT:
+ qh = (struct ehci_qh *) urb->hcpriv;
+ if (!qh)
+ break;
+ switch (qh->qh_state) {
+ case QH_STATE_LINKED:
+ intr_deschedule(oxu, qh);
+ /* FALL THROUGH */
+ case QH_STATE_IDLE:
+ qh_completions(oxu, qh);
+ break;
+ default:
+ oxu_dbg(oxu, "bogus qh %p state %d\n",
+ qh, qh->qh_state);
+ goto done;
+ }
+
+ /* reschedule QH iff another request is queued */
+ if (!list_empty(&qh->qtd_list)
+ && HC_IS_RUNNING(hcd->state)) {
+ int status;
+
+ status = qh_schedule(oxu, qh);
+ spin_unlock_irqrestore(&oxu->lock, flags);
+
+ if (status != 0) {
+ /* shouldn't happen often, but ...
+ * FIXME kill those tds' urbs
+ */
+ err("can't reschedule qh %p, err %d",
+ qh, status);
+ }
+ return status;
+ }
+ break;
+ }
+done:
+ spin_unlock_irqrestore(&oxu->lock, flags);
+ return 0;
+}
+
+/* Bulk qh holds the data toggle */
+static void oxu_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+ unsigned long flags;
+ struct ehci_qh *qh, *tmp;
+
+ /* ASSERT: any requests/urbs are being unlinked */
+ /* ASSERT: nobody can be submitting urbs for this any more */
+
+rescan:
+ spin_lock_irqsave(&oxu->lock, flags);
+ qh = ep->hcpriv;
+ if (!qh)
+ goto done;
+
+ /* endpoints can be iso streams. for now, we don't
+ * accelerate iso completions ... so spin a while.
+ */
+ if (qh->hw_info1 == 0) {
+ oxu_vdbg(oxu, "iso delay\n");
+ goto idle_timeout;
+ }
+
+ if (!HC_IS_RUNNING(hcd->state))
+ qh->qh_state = QH_STATE_IDLE;
+ switch (qh->qh_state) {
+ case QH_STATE_LINKED:
+ for (tmp = oxu->async->qh_next.qh;
+ tmp && tmp != qh;
+ tmp = tmp->qh_next.qh)
+ continue;
+ /* periodic qh self-unlinks on empty */
+ if (!tmp)
+ goto nogood;
+ unlink_async(oxu, qh);
+ /* FALL THROUGH */
+ case QH_STATE_UNLINK: /* wait for hw to finish? */
+idle_timeout:
+ spin_unlock_irqrestore(&oxu->lock, flags);
+ schedule_timeout_uninterruptible(1);
+ goto rescan;
+ case QH_STATE_IDLE: /* fully unlinked */
+ if (list_empty(&qh->qtd_list)) {
+ qh_put(qh);
+ break;
+ }
+ /* else FALL THROUGH */
+ default:
+nogood:
+ /* caller was supposed to have unlinked any requests;
+ * that's not our job. just leak this memory.
+ */
+ oxu_err(oxu, "qh %p (#%02x) state %d%s\n",
+ qh, ep->desc.bEndpointAddress, qh->qh_state,
+ list_empty(&qh->qtd_list) ? "" : "(has tds)");
+ break;
+ }
+ ep->hcpriv = NULL;
+done:
+ spin_unlock_irqrestore(&oxu->lock, flags);
+ return;
+}
+
+static int oxu_get_frame(struct usb_hcd *hcd)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+
+ return (readl(&oxu->regs->frame_index) >> 3) %
+ oxu->periodic_size;
+}
+
+/* Build "status change" packet (one or two bytes) from HC registers */
+static int oxu_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+ u32 temp, mask, status = 0;
+ int ports, i, retval = 1;
+ unsigned long flags;
+
+ /* if !USB_SUSPEND, root hub timers won't get shut down ... */
+ if (!HC_IS_RUNNING(hcd->state))
+ return 0;
+
+ /* init status to no-changes */
+ buf[0] = 0;
+ ports = HCS_N_PORTS(oxu->hcs_params);
+ if (ports > 7) {
+ buf[1] = 0;
+ retval++;
+ }
+
+ /* Some boards (mostly VIA?) report bogus overcurrent indications,
+ * causing massive log spam unless we completely ignore them. It
+ * may be relevant that VIA VT8235 controlers, where PORT_POWER is
+ * always set, seem to clear PORT_OCC and PORT_CSC when writing to
+ * PORT_POWER; that's surprising, but maybe within-spec.
+ */
+ if (!ignore_oc)
+ mask = PORT_CSC | PORT_PEC | PORT_OCC;
+ else
+ mask = PORT_CSC | PORT_PEC;
+
+ /* no hub change reports (bit 0) for now (power, ...) */
+
+ /* port N changes (bit N)? */
+ spin_lock_irqsave(&oxu->lock, flags);
+ for (i = 0; i < ports; i++) {
+ temp = readl(&oxu->regs->port_status[i]);
+
+ /*
+ * Return status information even for ports with OWNER set.
+ * Otherwise khubd wouldn't see the disconnect event when a
+ * high-speed device is switched over to the companion
+ * controller by the user.
+ */
+
+ if (!(temp & PORT_CONNECT))
+ oxu->reset_done[i] = 0;
+ if ((temp & mask) != 0 || ((temp & PORT_RESUME) != 0 &&
+ time_after_eq(jiffies, oxu->reset_done[i]))) {
+ if (i < 7)
+ buf[0] |= 1 << (i + 1);
+ else
+ buf[1] |= 1 << (i - 7);
+ status = STS_PCD;
+ }
+ }
+ /* FIXME autosuspend idle root hubs */
+ spin_unlock_irqrestore(&oxu->lock, flags);
+ return status ? retval : 0;
+}
+
+/* Returns the speed of a device attached to a port on the root hub. */
+static inline unsigned int oxu_port_speed(struct oxu_hcd *oxu,
+ unsigned int portsc)
+{
+ switch ((portsc >> 26) & 3) {
+ case 0:
+ return 0;
+ case 1:
+ return 1 << USB_PORT_FEAT_LOWSPEED;
+ case 2:
+ default:
+ return 1 << USB_PORT_FEAT_HIGHSPEED;
+ }
+}
+
+#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+static int oxu_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+ int ports = HCS_N_PORTS(oxu->hcs_params);
+ u32 __iomem *status_reg = &oxu->regs->port_status[wIndex - 1];
+ u32 temp, status;
+ unsigned long flags;
+ int retval = 0;
+ unsigned selector;
+
+ /*
+ * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+ * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+ * (track current state ourselves) ... blink for diagnostics,
+ * power, "this is the one", etc. EHCI spec supports this.
+ */
+
+ spin_lock_irqsave(&oxu->lock, flags);
+ switch (typeReq) {
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case ClearPortFeature:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ temp = readl(status_reg);
+
+ /*
+ * Even if OWNER is set, so the port is owned by the
+ * companion controller, khubd needs to be able to clear
+ * the port-change status bits (especially
+ * USB_PORT_FEAT_C_CONNECTION).
+ */
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ writel(temp & ~PORT_PE, status_reg);
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ writel((temp & ~PORT_RWC_BITS) | PORT_PEC, status_reg);
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ if (temp & PORT_RESET)
+ goto error;
+ if (temp & PORT_SUSPEND) {
+ if ((temp & PORT_PE) == 0)
+ goto error;
+ /* resume signaling for 20 msec */
+ temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
+ writel(temp | PORT_RESUME, status_reg);
+ oxu->reset_done[wIndex] = jiffies
+ + msecs_to_jiffies(20);
+ }
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ /* we auto-clear this feature */
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(oxu->hcs_params))
+ writel(temp & ~(PORT_RWC_BITS | PORT_POWER),
+ status_reg);
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ writel((temp & ~PORT_RWC_BITS) | PORT_CSC, status_reg);
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ writel((temp & ~PORT_RWC_BITS) | PORT_OCC, status_reg);
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ /* GetPortStatus clears reset */
+ break;
+ default:
+ goto error;
+ }
+ readl(&oxu->regs->command); /* unblock posted write */
+ break;
+ case GetHubDescriptor:
+ ehci_hub_descriptor(oxu, (struct usb_hub_descriptor *)
+ buf);
+ break;
+ case GetHubStatus:
+ /* no hub-wide feature/status flags */
+ memset(buf, 0, 4);
+ break;
+ case GetPortStatus:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ status = 0;
+ temp = readl(status_reg);
+
+ /* wPortChange bits */
+ if (temp & PORT_CSC)
+ status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+ if (temp & PORT_PEC)
+ status |= 1 << USB_PORT_FEAT_C_ENABLE;
+ if ((temp & PORT_OCC) && !ignore_oc)
+ status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
+
+ /* whoever resumes must GetPortStatus to complete it!! */
+ if (temp & PORT_RESUME) {
+
+ /* Remote Wakeup received? */
+ if (!oxu->reset_done[wIndex]) {
+ /* resume signaling for 20 msec */
+ oxu->reset_done[wIndex] = jiffies
+ + msecs_to_jiffies(20);
+ /* check the port again */
+ mod_timer(&oxu_to_hcd(oxu)->rh_timer,
+ oxu->reset_done[wIndex]);
+ }
+
+ /* resume completed? */
+ else if (time_after_eq(jiffies,
+ oxu->reset_done[wIndex])) {
+ status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+ oxu->reset_done[wIndex] = 0;
+
+ /* stop resume signaling */
+ temp = readl(status_reg);
+ writel(temp & ~(PORT_RWC_BITS | PORT_RESUME),
+ status_reg);
+ retval = handshake(oxu, status_reg,
+ PORT_RESUME, 0, 2000 /* 2msec */);
+ if (retval != 0) {
+ oxu_err(oxu,
+ "port %d resume error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+ temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+ }
+ }
+
+ /* whoever resets must GetPortStatus to complete it!! */
+ if ((temp & PORT_RESET)
+ && time_after_eq(jiffies,
+ oxu->reset_done[wIndex])) {
+ status |= 1 << USB_PORT_FEAT_C_RESET;
+ oxu->reset_done[wIndex] = 0;
+
+ /* force reset to complete */
+ writel(temp & ~(PORT_RWC_BITS | PORT_RESET),
+ status_reg);
+ /* REVISIT: some hardware needs 550+ usec to clear
+ * this bit; seems too long to spin routinely...
+ */
+ retval = handshake(oxu, status_reg,
+ PORT_RESET, 0, 750);
+ if (retval != 0) {
+ oxu_err(oxu, "port %d reset error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+
+ /* see what we found out */
+ temp = check_reset_complete(oxu, wIndex, status_reg,
+ readl(status_reg));
+ }
+
+ /* transfer dedicated ports to the companion hc */
+ if ((temp & PORT_CONNECT) &&
+ test_bit(wIndex, &oxu->companion_ports)) {
+ temp &= ~PORT_RWC_BITS;
+ temp |= PORT_OWNER;
+ writel(temp, status_reg);
+ oxu_dbg(oxu, "port %d --> companion\n", wIndex + 1);
+ temp = readl(status_reg);
+ }
+
+ /*
+ * Even if OWNER is set, there's no harm letting khubd
+ * see the wPortStatus values (they should all be 0 except
+ * for PORT_POWER anyway).
+ */
+
+ if (temp & PORT_CONNECT) {
+ status |= 1 << USB_PORT_FEAT_CONNECTION;
+ /* status may be from integrated TT */
+ status |= oxu_port_speed(oxu, temp);
+ }
+ if (temp & PORT_PE)
+ status |= 1 << USB_PORT_FEAT_ENABLE;
+ if (temp & (PORT_SUSPEND|PORT_RESUME))
+ status |= 1 << USB_PORT_FEAT_SUSPEND;
+ if (temp & PORT_OC)
+ status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+ if (temp & PORT_RESET)
+ status |= 1 << USB_PORT_FEAT_RESET;
+ if (temp & PORT_POWER)
+ status |= 1 << USB_PORT_FEAT_POWER;
+
+#ifndef OXU_VERBOSE_DEBUG
+ if (status & ~0xffff) /* only if wPortChange is interesting */
+#endif
+ dbg_port(oxu, "GetStatus", wIndex + 1, temp);
+ put_unaligned(cpu_to_le32(status), (__le32 *) buf);
+ break;
+ case SetHubFeature:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case SetPortFeature:
+ selector = wIndex >> 8;
+ wIndex &= 0xff;
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ temp = readl(status_reg);
+ if (temp & PORT_OWNER)
+ break;
+
+ temp &= ~PORT_RWC_BITS;
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ if ((temp & PORT_PE) == 0
+ || (temp & PORT_RESET) != 0)
+ goto error;
+ if (device_may_wakeup(&hcd->self.root_hub->dev))
+ temp |= PORT_WAKE_BITS;
+ writel(temp | PORT_SUSPEND, status_reg);
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(oxu->hcs_params))
+ writel(temp | PORT_POWER, status_reg);
+ break;
+ case USB_PORT_FEAT_RESET:
+ if (temp & PORT_RESUME)
+ goto error;
+ /* line status bits may report this as low speed,
+ * which can be fine if this root hub has a
+ * transaction translator built in.
+ */
+ oxu_vdbg(oxu, "port %d reset\n", wIndex + 1);
+ temp |= PORT_RESET;
+ temp &= ~PORT_PE;
+
+ /*
+ * caller must wait, then call GetPortStatus
+ * usb 2.0 spec says 50 ms resets on root
+ */
+ oxu->reset_done[wIndex] = jiffies
+ + msecs_to_jiffies(50);
+ writel(temp, status_reg);
+ break;
+
+ /* For downstream facing ports (these): one hub port is put
+ * into test mode according to USB2 11.24.2.13, then the hub
+ * must be reset (which for root hub now means rmmod+modprobe,
+ * or else system reboot). See EHCI 2.3.9 and 4.14 for info
+ * about the EHCI-specific stuff.
+ */
+ case USB_PORT_FEAT_TEST:
+ if (!selector || selector > 5)
+ goto error;
+ ehci_quiesce(oxu);
+ ehci_halt(oxu);
+ temp |= selector << 16;
+ writel(temp, status_reg);
+ break;
+
+ default:
+ goto error;
+ }
+ readl(&oxu->regs->command); /* unblock posted writes */
+ break;
+
+ default:
+error:
+ /* "stall" on error */
+ retval = -EPIPE;
+ }
+ spin_unlock_irqrestore(&oxu->lock, flags);
+ return retval;
+}
+
+#ifdef CONFIG_PM
+
+static int oxu_bus_suspend(struct usb_hcd *hcd)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+ int port;
+ int mask;
+
+ oxu_dbg(oxu, "suspend root hub\n");
+
+ if (time_before(jiffies, oxu->next_statechange))
+ msleep(5);
+
+ port = HCS_N_PORTS(oxu->hcs_params);
+ spin_lock_irq(&oxu->lock);
+
+ /* stop schedules, clean any completed work */
+ if (HC_IS_RUNNING(hcd->state)) {
+ ehci_quiesce(oxu);
+ hcd->state = HC_STATE_QUIESCING;
+ }
+ oxu->command = readl(&oxu->regs->command);
+ if (oxu->reclaim)
+ oxu->reclaim_ready = 1;
+ ehci_work(oxu);
+
+ /* Unlike other USB host controller types, EHCI doesn't have
+ * any notion of "global" or bus-wide suspend. The driver has
+ * to manually suspend all the active unsuspended ports, and
+ * then manually resume them in the bus_resume() routine.
+ */
+ oxu->bus_suspended = 0;
+ while (port--) {
+ u32 __iomem *reg = &oxu->regs->port_status[port];
+ u32 t1 = readl(reg) & ~PORT_RWC_BITS;
+ u32 t2 = t1;
+
+ /* keep track of which ports we suspend */
+ if ((t1 & PORT_PE) && !(t1 & PORT_OWNER) &&
+ !(t1 & PORT_SUSPEND)) {
+ t2 |= PORT_SUSPEND;
+ set_bit(port, &oxu->bus_suspended);
+ }
+
+ /* enable remote wakeup on all ports */
+ if (device_may_wakeup(&hcd->self.root_hub->dev))
+ t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
+ else
+ t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
+
+ if (t1 != t2) {
+ oxu_vdbg(oxu, "port %d, %08x -> %08x\n",
+ port + 1, t1, t2);
+ writel(t2, reg);
+ }
+ }
+
+ /* turn off now-idle HC */
+ del_timer_sync(&oxu->watchdog);
+ ehci_halt(oxu);
+ hcd->state = HC_STATE_SUSPENDED;
+
+ /* allow remote wakeup */
+ mask = INTR_MASK;
+ if (!device_may_wakeup(&hcd->self.root_hub->dev))
+ mask &= ~STS_PCD;
+ writel(mask, &oxu->regs->intr_enable);
+ readl(&oxu->regs->intr_enable);
+
+ oxu->next_statechange = jiffies + msecs_to_jiffies(10);
+ spin_unlock_irq(&oxu->lock);
+ return 0;
+}
+
+/* Caller has locked the root hub, and should reset/reinit on error */
+static int oxu_bus_resume(struct usb_hcd *hcd)
+{
+ struct oxu_hcd *oxu = hcd_to_oxu(hcd);
+ u32 temp;
+ int i;
+
+ if (time_before(jiffies, oxu->next_statechange))
+ msleep(5);
+ spin_lock_irq(&oxu->lock);
+
+ /* Ideally and we've got a real resume here, and no port's power
+ * was lost. (For PCI, that means Vaux was maintained.) But we
+ * could instead be restoring a swsusp snapshot -- so that BIOS was
+ * the last user of the controller, not reset/pm hardware keeping
+ * state we gave to it.
+ */
+ temp = readl(&oxu->regs->intr_enable);
+ oxu_dbg(oxu, "resume root hub%s\n", temp ? "" : " after power loss");
+
+ /* at least some APM implementations will try to deliver
+ * IRQs right away, so delay them until we're ready.
+ */
+ writel(0, &oxu->regs->intr_enable);
+
+ /* re-init operational registers */
+ writel(0, &oxu->regs->segment);
+ writel(oxu->periodic_dma, &oxu->regs->frame_list);
+ writel((u32) oxu->async->qh_dma, &oxu->regs->async_next);
+
+ /* restore CMD_RUN, framelist size, and irq threshold */
+ writel(oxu->command, &oxu->regs->command);
+
+ /* Some controller/firmware combinations need a delay during which
+ * they set up the port statuses. See Bugzilla #8190. */
+ mdelay(8);
+
+ /* manually resume the ports we suspended during bus_suspend() */
+ i = HCS_N_PORTS(oxu->hcs_params);
+ while (i--) {
+ temp = readl(&oxu->regs->port_status[i]);
+ temp &= ~(PORT_RWC_BITS
+ | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
+ if (test_bit(i, &oxu->bus_suspended) && (temp & PORT_SUSPEND)) {
+ oxu->reset_done[i] = jiffies + msecs_to_jiffies(20);
+ temp |= PORT_RESUME;
+ }
+ writel(temp, &oxu->regs->port_status[i]);
+ }
+ i = HCS_N_PORTS(oxu->hcs_params);
+ mdelay(20);
+ while (i--) {
+ temp = readl(&oxu->regs->port_status[i]);
+ if (test_bit(i, &oxu->bus_suspended) && (temp & PORT_SUSPEND)) {
+ temp &= ~(PORT_RWC_BITS | PORT_RESUME);
+ writel(temp, &oxu->regs->port_status[i]);
+ oxu_vdbg(oxu, "resumed port %d\n", i + 1);
+ }
+ }
+ (void) readl(&oxu->regs->command);
+
+ /* maybe re-activate the schedule(s) */
+ temp = 0;
+ if (oxu->async->qh_next.qh)
+ temp |= CMD_ASE;
+ if (oxu->periodic_sched)
+ temp |= CMD_PSE;
+ if (temp) {
+ oxu->command |= temp;
+ writel(oxu->command, &oxu->regs->command);
+ }
+
+ oxu->next_statechange = jiffies + msecs_to_jiffies(5);
+ hcd->state = HC_STATE_RUNNING;
+
+ /* Now we can safely re-enable irqs */
+ writel(INTR_MASK, &oxu->regs->intr_enable);
+
+ spin_unlock_irq(&oxu->lock);
+ return 0;
+}
+
+#else
+
+static int oxu_bus_suspend(struct usb_hcd *hcd)
+{
+ return 0;
+}
+
+static int oxu_bus_resume(struct usb_hcd *hcd)
+{
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+static const struct hc_driver oxu_hc_driver = {
+ .description = "oxu210hp_hcd",
+ .product_desc = "oxu210hp HCD",
+ .hcd_priv_size = sizeof(struct oxu_hcd),
+
+ /*
+ * Generic hardware linkage
+ */
+ .irq = oxu_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * Basic lifecycle operations
+ */
+ .reset = oxu_reset,
+ .start = oxu_run,
+ .stop = oxu_stop,
+ .shutdown = oxu_shutdown,
+
+ /*
+ * Managing i/o requests and associated device resources
+ */
+ .urb_enqueue = oxu_urb_enqueue,
+ .urb_dequeue = oxu_urb_dequeue,
+ .endpoint_disable = oxu_endpoint_disable,
+
+ /*
+ * Scheduling support
+ */
+ .get_frame_number = oxu_get_frame,
+
+ /*
+ * Root hub support
+ */
+ .hub_status_data = oxu_hub_status_data,
+ .hub_control = oxu_hub_control,
+ .bus_suspend = oxu_bus_suspend,
+ .bus_resume = oxu_bus_resume,
+};
+
+/*
+ * Module stuff
+ */
+
+static void oxu_configuration(struct platform_device *pdev, void *base)
+{
+ u32 tmp;
+
+ /* Initialize top level registers.
+ * First write ever
+ */
+ oxu_writel(base, OXU_HOSTIFCONFIG, 0x0000037D);
+ oxu_writel(base, OXU_SOFTRESET, OXU_SRESET);
+ oxu_writel(base, OXU_HOSTIFCONFIG, 0x0000037D);
+
+ tmp = oxu_readl(base, OXU_PIOBURSTREADCTRL);
+ oxu_writel(base, OXU_PIOBURSTREADCTRL, tmp | 0x0040);
+
+ oxu_writel(base, OXU_ASO, OXU_SPHPOEN | OXU_OVRCCURPUPDEN |
+ OXU_COMPARATOR | OXU_ASO_OP);
+
+ tmp = oxu_readl(base, OXU_CLKCTRL_SET);
+ oxu_writel(base, OXU_CLKCTRL_SET, tmp | OXU_SYSCLKEN | OXU_USBOTGCLKEN);
+
+ /* Clear all top interrupt enable */
+ oxu_writel(base, OXU_CHIPIRQEN_CLR, 0xff);
+
+ /* Clear all top interrupt status */
+ oxu_writel(base, OXU_CHIPIRQSTATUS, 0xff);
+
+ /* Enable all needed top interrupt except OTG SPH core */
+ oxu_writel(base, OXU_CHIPIRQEN_SET, OXU_USBSPHLPWUI | OXU_USBOTGLPWUI);
+}
+
+static int oxu_verify_id(struct platform_device *pdev, void *base)
+{
+ u32 id;
+ char *bo[] = {
+ "reserved",
+ "128-pin LQFP",
+ "84-pin TFBGA",
+ "reserved",
+ };
+
+ /* Read controller signature register to find a match */
+ id = oxu_readl(base, OXU_DEVICEID);
+ dev_info(&pdev->dev, "device ID %x\n", id);
+ if ((id & OXU_REV_MASK) != (OXU_REV_2100 << OXU_REV_SHIFT))
+ return -1;
+
+ dev_info(&pdev->dev, "found device %x %s (%04x:%04x)\n",
+ id >> OXU_REV_SHIFT,
+ bo[(id & OXU_BO_MASK) >> OXU_BO_SHIFT],
+ (id & OXU_MAJ_REV_MASK) >> OXU_MAJ_REV_SHIFT,
+ (id & OXU_MIN_REV_MASK) >> OXU_MIN_REV_SHIFT);
+
+ return 0;
+}
+
+static const struct hc_driver oxu_hc_driver;
+static struct usb_hcd *oxu_create(struct platform_device *pdev,
+ unsigned long memstart, unsigned long memlen,
+ void *base, int irq, int otg)
+{
+ struct device *dev = &pdev->dev;
+
+ struct usb_hcd *hcd;
+ struct oxu_hcd *oxu;
+ int ret;
+
+ /* Set endian mode and host mode */
+ oxu_writel(base + (otg ? OXU_OTG_CORE_OFFSET : OXU_SPH_CORE_OFFSET),
+ OXU_USBMODE,
+ OXU_CM_HOST_ONLY | OXU_ES_LITTLE | OXU_VBPS);
+
+ hcd = usb_create_hcd(&oxu_hc_driver, dev,
+ otg ? "oxu210hp_otg" : "oxu210hp_sph");
+ if (!hcd)
+ return ERR_PTR(-ENOMEM);
+
+ hcd->rsrc_start = memstart;
+ hcd->rsrc_len = memlen;
+ hcd->regs = base;
+ hcd->irq = irq;
+ hcd->state = HC_STATE_HALT;
+
+ oxu = hcd_to_oxu(hcd);
+ oxu->is_otg = otg;
+
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ return hcd;
+}
+
+static int oxu_init(struct platform_device *pdev,
+ unsigned long memstart, unsigned long memlen,
+ void *base, int irq)
+{
+ struct oxu_info *info = platform_get_drvdata(pdev);
+ struct usb_hcd *hcd;
+ int ret;
+
+ /* First time configuration at start up */
+ oxu_configuration(pdev, base);
+
+ ret = oxu_verify_id(pdev, base);
+ if (ret) {
+ dev_err(&pdev->dev, "no devices found!\n");
+ return -ENODEV;
+ }
+
+ /* Create the OTG controller */
+ hcd = oxu_create(pdev, memstart, memlen, base, irq, 1);
+ if (IS_ERR(hcd)) {
+ dev_err(&pdev->dev, "cannot create OTG controller!\n");
+ ret = PTR_ERR(hcd);
+ goto error_create_otg;
+ }
+ info->hcd[0] = hcd;
+
+ /* Create the SPH host controller */
+ hcd = oxu_create(pdev, memstart, memlen, base, irq, 0);
+ if (IS_ERR(hcd)) {
+ dev_err(&pdev->dev, "cannot create SPH controller!\n");
+ ret = PTR_ERR(hcd);
+ goto error_create_sph;
+ }
+ info->hcd[1] = hcd;
+
+ oxu_writel(base, OXU_CHIPIRQEN_SET,
+ oxu_readl(base, OXU_CHIPIRQEN_SET) | 3);
+
+ return 0;
+
+error_create_sph:
+ usb_remove_hcd(info->hcd[0]);
+ usb_put_hcd(info->hcd[0]);
+
+error_create_otg:
+ return ret;
+}
+
+static int oxu_drv_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ void *base;
+ unsigned long memstart, memlen;
+ int irq, ret;
+ struct oxu_info *info;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ /*
+ * Get the platform resources
+ */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "no IRQ! Check %s setup!\n", dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+ irq = res->start;
+ dev_dbg(&pdev->dev, "IRQ resource %d\n", irq);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no registers address! Check %s setup!\n",
+ dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+ memstart = res->start;
+ memlen = res->end - res->start + 1;
+ dev_dbg(&pdev->dev, "MEM resource %lx-%lx\n", memstart, memlen);
+ if (!request_mem_region(memstart, memlen,
+ oxu_hc_driver.description)) {
+ dev_dbg(&pdev->dev, "memory area already in use\n");
+ return -EBUSY;
+ }
+
+ ret = set_irq_type(irq, IRQF_TRIGGER_FALLING);
+ if (ret) {
+ dev_err(&pdev->dev, "error setting irq type\n");
+ ret = -EFAULT;
+ goto error_set_irq_type;
+ }
+
+ base = ioremap(memstart, memlen);
+ if (!base) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ ret = -EFAULT;
+ goto error_ioremap;
+ }
+
+ /* Allocate a driver data struct to hold useful info for both
+ * SPH & OTG devices
+ */
+ info = kzalloc(sizeof(struct oxu_info), GFP_KERNEL);
+ if (!info) {
+ dev_dbg(&pdev->dev, "error allocating memory\n");
+ ret = -EFAULT;
+ goto error_alloc;
+ }
+ platform_set_drvdata(pdev, info);
+
+ ret = oxu_init(pdev, memstart, memlen, base, irq);
+ if (ret < 0) {
+ dev_dbg(&pdev->dev, "cannot init USB devices\n");
+ goto error_init;
+ }
+
+ dev_info(&pdev->dev, "devices enabled and running\n");
+ platform_set_drvdata(pdev, info);
+
+ return 0;
+
+error_init:
+ kfree(info);
+ platform_set_drvdata(pdev, NULL);
+
+error_alloc:
+ iounmap(base);
+
+error_set_irq_type:
+error_ioremap:
+ release_mem_region(memstart, memlen);
+
+ dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), ret);
+ return ret;
+}
+
+static void oxu_remove(struct platform_device *pdev, struct usb_hcd *hcd)
+{
+ usb_remove_hcd(hcd);
+ usb_put_hcd(hcd);
+}
+
+static int oxu_drv_remove(struct platform_device *pdev)
+{
+ struct oxu_info *info = platform_get_drvdata(pdev);
+ unsigned long memstart = info->hcd[0]->rsrc_start,
+ memlen = info->hcd[0]->rsrc_len;
+ void *base = info->hcd[0]->regs;
+
+ oxu_remove(pdev, info->hcd[0]);
+ oxu_remove(pdev, info->hcd[1]);
+
+ iounmap(base);
+ release_mem_region(memstart, memlen);
+
+ kfree(info);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static void oxu_drv_shutdown(struct platform_device *pdev)
+{
+ oxu_drv_remove(pdev);
+}
+
+#if 0
+/* FIXME: TODO */
+static int oxu_drv_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+ return 0;
+}
+
+static int oxu_drv_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+ return 0;
+}
+#else
+#define oxu_drv_suspend NULL
+#define oxu_drv_resume NULL
+#endif
+
+static struct platform_driver oxu_driver = {
+ .probe = oxu_drv_probe,
+ .remove = oxu_drv_remove,
+ .shutdown = oxu_drv_shutdown,
+ .suspend = oxu_drv_suspend,
+ .resume = oxu_drv_resume,
+ .driver = {
+ .name = "oxu210hp-hcd",
+ .bus = &platform_bus_type
+ }
+};
+
+static int __init oxu_module_init(void)
+{
+ int retval = 0;
+
+ retval = platform_driver_register(&oxu_driver);
+ if (retval < 0)
+ return retval;
+
+ return retval;
+}
+
+static void __exit oxu_module_cleanup(void)
+{
+ platform_driver_unregister(&oxu_driver);
+}
+
+module_init(oxu_module_init);
+module_exit(oxu_module_cleanup);
+
+MODULE_DESCRIPTION("Oxford OXU210HP HCD driver - ver. " DRIVER_VERSION);
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/oxu210hp.h b/drivers/usb/host/oxu210hp.h
new file mode 100644
index 000000000000..8910e271cc7d
--- /dev/null
+++ b/drivers/usb/host/oxu210hp.h
@@ -0,0 +1,447 @@
+/*
+ * Host interface registers
+ */
+
+#define OXU_DEVICEID 0x00
+ #define OXU_REV_MASK 0xffff0000
+ #define OXU_REV_SHIFT 16
+ #define OXU_REV_2100 0x2100
+ #define OXU_BO_SHIFT 8
+ #define OXU_BO_MASK (0x3 << OXU_BO_SHIFT)
+ #define OXU_MAJ_REV_SHIFT 4
+ #define OXU_MAJ_REV_MASK (0xf << OXU_MAJ_REV_SHIFT)
+ #define OXU_MIN_REV_SHIFT 0
+ #define OXU_MIN_REV_MASK (0xf << OXU_MIN_REV_SHIFT)
+#define OXU_HOSTIFCONFIG 0x04
+#define OXU_SOFTRESET 0x08
+ #define OXU_SRESET (1 << 0)
+
+#define OXU_PIOBURSTREADCTRL 0x0C
+
+#define OXU_CHIPIRQSTATUS 0x10
+#define OXU_CHIPIRQEN_SET 0x14
+#define OXU_CHIPIRQEN_CLR 0x18
+ #define OXU_USBSPHLPWUI 0x00000080
+ #define OXU_USBOTGLPWUI 0x00000040
+ #define OXU_USBSPHI 0x00000002
+ #define OXU_USBOTGI 0x00000001
+
+#define OXU_CLKCTRL_SET 0x1C
+ #define OXU_SYSCLKEN 0x00000008
+ #define OXU_USBSPHCLKEN 0x00000002
+ #define OXU_USBOTGCLKEN 0x00000001
+
+#define OXU_ASO 0x68
+ #define OXU_SPHPOEN 0x00000100
+ #define OXU_OVRCCURPUPDEN 0x00000800
+ #define OXU_ASO_OP (1 << 10)
+ #define OXU_COMPARATOR 0x000004000
+
+#define OXU_USBMODE 0x1A8
+ #define OXU_VBPS 0x00000020
+ #define OXU_ES_LITTLE 0x00000000
+ #define OXU_CM_HOST_ONLY 0x00000003
+
+/*
+ * Proper EHCI structs & defines
+ */
+
+/* Magic numbers that can affect system performance */
+#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
+#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
+#define EHCI_TUNE_RL_TT 0
+#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
+#define EHCI_TUNE_MULT_TT 1
+#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
+
+struct oxu_hcd;
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct ehci_caps {
+ /* these fields are specified as 8 and 16 bit registers,
+ * but some hosts can't perform 8 or 16 bit PCI accesses.
+ */
+ u32 hc_capbase;
+#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
+#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
+ u32 hcs_params; /* HCSPARAMS - offset 0x4 */
+#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */
+#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
+#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
+#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
+#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
+#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
+#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
+
+ u32 hcc_params; /* HCCPARAMS - offset 0x8 */
+#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */
+#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
+#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
+#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */
+ u8 portroute[8]; /* nibbles for routing - offset 0xC */
+} __attribute__ ((packed));
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct ehci_regs {
+ /* USBCMD: offset 0x00 */
+ u32 command;
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK (1<<11) /* enable "park" on async qh */
+#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
+#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
+#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
+#define CMD_ASE (1<<5) /* async schedule enable */
+#define CMD_PSE (1<<4) /* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET (1<<1) /* reset HC not bus */
+#define CMD_RUN (1<<0) /* start/stop HC */
+
+ /* USBSTS: offset 0x04 */
+ u32 status;
+#define STS_ASS (1<<15) /* Async Schedule Status */
+#define STS_PSS (1<<14) /* Periodic Schedule Status */
+#define STS_RECL (1<<13) /* Reclamation */
+#define STS_HALT (1<<12) /* Not running (any reason) */
+/* some bits reserved */
+ /* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA (1<<5) /* Interrupted on async advance */
+#define STS_FATAL (1<<4) /* such as some PCI access errors */
+#define STS_FLR (1<<3) /* frame list rolled over */
+#define STS_PCD (1<<2) /* port change detect */
+#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
+#define STS_INT (1<<0) /* "normal" completion (short, ...) */
+
+#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
+
+ /* USBINTR: offset 0x08 */
+ u32 intr_enable;
+
+ /* FRINDEX: offset 0x0C */
+ u32 frame_index; /* current microframe number */
+ /* CTRLDSSEGMENT: offset 0x10 */
+ u32 segment; /* address bits 63:32 if needed */
+ /* PERIODICLISTBASE: offset 0x14 */
+ u32 frame_list; /* points to periodic list */
+ /* ASYNCLISTADDR: offset 0x18 */
+ u32 async_next; /* address of next async queue head */
+
+ u32 reserved[9];
+
+ /* CONFIGFLAG: offset 0x40 */
+ u32 configured_flag;
+#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
+
+ /* PORTSC: offset 0x44 */
+ u32 port_status[0]; /* up to N_PORTS */
+/* 31:23 reserved */
+#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
+#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
+#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */
+/* 19:16 for port testing */
+#define PORT_LED_OFF (0<<14)
+#define PORT_LED_AMBER (1<<14)
+#define PORT_LED_GREEN (2<<14)
+#define PORT_LED_MASK (3<<14)
+#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
+#define PORT_POWER (1<<12) /* true: has power (see PPC) */
+#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */
+/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+/* 9 reserved */
+#define PORT_RESET (1<<8) /* reset port */
+#define PORT_SUSPEND (1<<7) /* suspend port */
+#define PORT_RESUME (1<<6) /* resume it */
+#define PORT_OCC (1<<5) /* over current change */
+#define PORT_OC (1<<4) /* over current active */
+#define PORT_PEC (1<<3) /* port enable change */
+#define PORT_PE (1<<2) /* port enable */
+#define PORT_CSC (1<<1) /* connect status change */
+#define PORT_CONNECT (1<<0) /* device connected */
+#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
+} __attribute__ ((packed));
+
+/* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console. (nonstandard enumeration.)
+ */
+struct ehci_dbg_port {
+ u32 control;
+#define DBGP_OWNER (1<<30)
+#define DBGP_ENABLED (1<<28)
+#define DBGP_DONE (1<<16)
+#define DBGP_INUSE (1<<10)
+#define DBGP_ERRCODE(x) (((x)>>7)&0x07)
+# define DBGP_ERR_BAD 1
+# define DBGP_ERR_SIGNAL 2
+#define DBGP_ERROR (1<<6)
+#define DBGP_GO (1<<5)
+#define DBGP_OUT (1<<4)
+#define DBGP_LEN(x) (((x)>>0)&0x0f)
+ u32 pids;
+#define DBGP_PID_GET(x) (((x)>>16)&0xff)
+#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok))
+ u32 data03;
+ u32 data47;
+ u32 address;
+#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep))
+} __attribute__ ((packed));
+
+
+#define QTD_NEXT(dma) cpu_to_le32((u32)dma)
+
+/*
+ * EHCI Specification 0.95 Section 3.5
+ * QTD: describe data transfer components (buffer, direction, ...)
+ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
+ *
+ * These are associated only with "QH" (Queue Head) structures,
+ * used with control, bulk, and interrupt transfers.
+ */
+struct ehci_qtd {
+ /* first part defined by EHCI spec */
+ __le32 hw_next; /* see EHCI 3.5.1 */
+ __le32 hw_alt_next; /* see EHCI 3.5.2 */
+ __le32 hw_token; /* see EHCI 3.5.3 */
+#define QTD_TOGGLE (1 << 31) /* data toggle */
+#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
+#define QTD_IOC (1 << 15) /* interrupt on complete */
+#define QTD_CERR(tok) (((tok)>>10) & 0x3)
+#define QTD_PID(tok) (((tok)>>8) & 0x3)
+#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
+#define QTD_STS_HALT (1 << 6) /* halted on error */
+#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
+#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
+#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
+#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
+#define QTD_STS_STS (1 << 1) /* split transaction state */
+#define QTD_STS_PING (1 << 0) /* issue PING? */
+ __le32 hw_buf[5]; /* see EHCI 3.5.4 */
+ __le32 hw_buf_hi[5]; /* Appendix B */
+
+ /* the rest is HCD-private */
+ dma_addr_t qtd_dma; /* qtd address */
+ struct list_head qtd_list; /* sw qtd list */
+ struct urb *urb; /* qtd's urb */
+ size_t length; /* length of buffer */
+
+ u32 qtd_buffer_len;
+ void *buffer;
+ dma_addr_t buffer_dma;
+ void *transfer_buffer;
+ void *transfer_dma;
+} __attribute__ ((aligned(32)));
+
+/* mask NakCnt+T in qh->hw_alt_next */
+#define QTD_MASK __constant_cpu_to_le32 (~0x1f)
+
+#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
+
+/* Type tag from {qh, itd, sitd, fstn}->hw_next */
+#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1))
+
+/* values for that type tag */
+#define Q_TYPE_QH __constant_cpu_to_le32 (1 << 1)
+
+/* next async queue entry, or pointer to interrupt/periodic QH */
+#define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
+
+/* for periodic/async schedules and qtd lists, mark end of list */
+#define EHCI_LIST_END __constant_cpu_to_le32(1) /* "null pointer" to hw */
+
+/*
+ * Entries in periodic shadow table are pointers to one of four kinds
+ * of data structure. That's dictated by the hardware; a type tag is
+ * encoded in the low bits of the hardware's periodic schedule. Use
+ * Q_NEXT_TYPE to get the tag.
+ *
+ * For entries in the async schedule, the type tag always says "qh".
+ */
+union ehci_shadow {
+ struct ehci_qh *qh; /* Q_TYPE_QH */
+ __le32 *hw_next; /* (all types) */
+ void *ptr;
+};
+
+/*
+ * EHCI Specification 0.95 Section 3.6
+ * QH: describes control/bulk/interrupt endpoints
+ * See Fig 3-7 "Queue Head Structure Layout".
+ *
+ * These appear in both the async and (for interrupt) periodic schedules.
+ */
+
+struct ehci_qh {
+ /* first part defined by EHCI spec */
+ __le32 hw_next; /* see EHCI 3.6.1 */
+ __le32 hw_info1; /* see EHCI 3.6.2 */
+#define QH_HEAD 0x00008000
+ __le32 hw_info2; /* see EHCI 3.6.2 */
+#define QH_SMASK 0x000000ff
+#define QH_CMASK 0x0000ff00
+#define QH_HUBADDR 0x007f0000
+#define QH_HUBPORT 0x3f800000
+#define QH_MULT 0xc0000000
+ __le32 hw_current; /* qtd list - see EHCI 3.6.4 */
+
+ /* qtd overlay (hardware parts of a struct ehci_qtd) */
+ __le32 hw_qtd_next;
+ __le32 hw_alt_next;
+ __le32 hw_token;
+ __le32 hw_buf[5];
+ __le32 hw_buf_hi[5];
+
+ /* the rest is HCD-private */
+ dma_addr_t qh_dma; /* address of qh */
+ union ehci_shadow qh_next; /* ptr to qh; or periodic */
+ struct list_head qtd_list; /* sw qtd list */
+ struct ehci_qtd *dummy;
+ struct ehci_qh *reclaim; /* next to reclaim */
+
+ struct oxu_hcd *oxu;
+ struct kref kref;
+ unsigned stamp;
+
+ u8 qh_state;
+#define QH_STATE_LINKED 1 /* HC sees this */
+#define QH_STATE_UNLINK 2 /* HC may still see this */
+#define QH_STATE_IDLE 3 /* HC doesn't see this */
+#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on reclaim q */
+#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
+
+ /* periodic schedule info */
+ u8 usecs; /* intr bandwidth */
+ u8 gap_uf; /* uframes split/csplit gap */
+ u8 c_usecs; /* ... split completion bw */
+ u16 tt_usecs; /* tt downstream bandwidth */
+ unsigned short period; /* polling interval */
+ unsigned short start; /* where polling starts */
+#define NO_FRAME ((unsigned short)~0) /* pick new start */
+ struct usb_device *dev; /* access to TT */
+} __attribute__ ((aligned(32)));
+
+/*
+ * Proper OXU210HP structs
+ */
+
+#define OXU_OTG_CORE_OFFSET 0x00400
+#define OXU_OTG_CAP_OFFSET (OXU_OTG_CORE_OFFSET + 0x100)
+#define OXU_SPH_CORE_OFFSET 0x00800
+#define OXU_SPH_CAP_OFFSET (OXU_SPH_CORE_OFFSET + 0x100)
+
+#define OXU_OTG_MEM 0xE000
+#define OXU_SPH_MEM 0x16000
+
+/* Only how many elements & element structure are specifies here. */
+/* 2 host controllers are enabled - total size <= 28 kbytes */
+#define DEFAULT_I_TDPS 1024
+#define QHEAD_NUM 16
+#define QTD_NUM 32
+#define SITD_NUM 8
+#define MURB_NUM 8
+
+#define BUFFER_NUM 8
+#define BUFFER_SIZE 512
+
+struct oxu_info {
+ struct usb_hcd *hcd[2];
+};
+
+struct oxu_buf {
+ u8 buffer[BUFFER_SIZE];
+} __attribute__ ((aligned(BUFFER_SIZE)));
+
+struct oxu_onchip_mem {
+ struct oxu_buf db_pool[BUFFER_NUM];
+
+ u32 frame_list[DEFAULT_I_TDPS];
+ struct ehci_qh qh_pool[QHEAD_NUM];
+ struct ehci_qtd qtd_pool[QTD_NUM];
+} __attribute__ ((aligned(4 << 10)));
+
+#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
+
+struct oxu_murb {
+ struct urb urb;
+ struct urb *main;
+ u8 last;
+};
+
+struct oxu_hcd { /* one per controller */
+ unsigned int is_otg:1;
+
+ u8 qh_used[QHEAD_NUM];
+ u8 qtd_used[QTD_NUM];
+ u8 db_used[BUFFER_NUM];
+ u8 murb_used[MURB_NUM];
+
+ struct oxu_onchip_mem __iomem *mem;
+ spinlock_t mem_lock;
+
+ struct timer_list urb_timer;
+
+ struct ehci_caps __iomem *caps;
+ struct ehci_regs __iomem *regs;
+
+ __u32 hcs_params; /* cached register copy */
+ spinlock_t lock;
+
+ /* async schedule support */
+ struct ehci_qh *async;
+ struct ehci_qh *reclaim;
+ unsigned reclaim_ready:1;
+ unsigned scanning:1;
+
+ /* periodic schedule support */
+ unsigned periodic_size;
+ __le32 *periodic; /* hw periodic table */
+ dma_addr_t periodic_dma;
+ unsigned i_thresh; /* uframes HC might cache */
+
+ union ehci_shadow *pshadow; /* mirror hw periodic table */
+ int next_uframe; /* scan periodic, start here */
+ unsigned periodic_sched; /* periodic activity count */
+
+ /* per root hub port */
+ unsigned long reset_done[EHCI_MAX_ROOT_PORTS];
+ /* bit vectors (one bit per port) */
+ unsigned long bus_suspended; /* which ports were
+ * already suspended at the
+ * start of a bus suspend
+ */
+ unsigned long companion_ports;/* which ports are dedicated
+ * to the companion controller
+ */
+
+ struct timer_list watchdog;
+ unsigned long actions;
+ unsigned stamp;
+ unsigned long next_statechange;
+ u32 command;
+
+ /* SILICON QUIRKS */
+ struct list_head urb_list; /* this is the head to urb
+ * queue that didn't get enough
+ * resources
+ */
+ struct oxu_murb *murb_pool; /* murb per split big urb */
+ unsigned urb_len;
+
+ u8 sbrn; /* packed release number */
+};
+
+#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
+#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
+#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
+#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
+
+enum ehci_timer_action {
+ TIMER_IO_WATCHDOG,
+ TIMER_IAA_WATCHDOG,
+ TIMER_ASYNC_SHRINK,
+ TIMER_ASYNC_OFF,
+};
+
+#include <linux/oxu210hp.h>
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index ae6e70edd745..75b69847918e 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -172,9 +172,9 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
if (!mmio_resource_enabled(pdev, 0))
return;
- base = ioremap_nocache(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- if (base == NULL) return;
+ base = pci_ioremap_bar(pdev, 0);
+ if (base == NULL)
+ return;
/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
#ifndef __hppa__
@@ -221,9 +221,9 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
if (!mmio_resource_enabled(pdev, 0))
return;
- base = ioremap_nocache(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- if (base == NULL) return;
+ base = pci_ioremap_bar(pdev, 0);
+ if (base == NULL)
+ return;
cap_length = readb(base);
op_reg_base = base + cap_length;
@@ -271,7 +271,7 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
/* if boot firmware now owns EHCI, spin till
* it hands it over.
*/
- msec = 5000;
+ msec = 1000;
while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) {
tried_handoff = 1;
msleep(10);
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index c21f14e0666a..319041205b57 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2275,7 +2275,6 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
return 0;
}
-#define resource_len(r) (((r)->end - (r)->start) + 1)
static int __init r8a66597_probe(struct platform_device *pdev)
{
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
@@ -2296,11 +2295,10 @@ static int __init r8a66597_probe(struct platform_device *pdev)
goto clean_up;
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- (char *)hcd_name);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
- dev_err(&pdev->dev, "platform_get_resource_byname error.\n");
+ dev_err(&pdev->dev, "platform_get_resource error.\n");
goto clean_up;
}
@@ -2315,7 +2313,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
irq = ires->start;
irq_trigger = ires->flags & IRQF_TRIGGER_MASK;
- reg = ioremap(res->start, resource_len(res));
+ reg = ioremap(res->start, resource_size(res));
if (reg == NULL) {
ret = -ENOMEM;
dev_err(&pdev->dev, "ioremap error.\n");
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index cf5e4cf7ea42..4e221060f58c 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -942,6 +942,8 @@ static struct pci_driver uhci_pci_driver = {
#ifdef CONFIG_PM
.suspend = usb_hcd_pci_suspend,
+ .suspend_late = usb_hcd_pci_suspend_late,
+ .resume_early = usb_hcd_pci_resume_early,
.resume = usb_hcd_pci_resume,
#endif /* PM */
};
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 885867a86de8..4541dfcea88f 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -350,17 +350,16 @@ static int mts_scsi_abort(struct scsi_cmnd *srb)
static int mts_scsi_host_reset(struct scsi_cmnd *srb)
{
struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
- int result, rc;
+ int result;
MTS_DEBUG_GOT_HERE();
mts_debug_dump(desc);
- rc = usb_lock_device_for_reset(desc->usb_dev, desc->usb_intf);
- if (rc < 0)
- return FAILED;
- result = usb_reset_device(desc->usb_dev);
- if (rc)
+ result = usb_lock_device_for_reset(desc->usb_dev, desc->usb_intf);
+ if (result == 0) {
+ result = usb_reset_device(desc->usb_dev);
usb_unlock_device(desc->usb_dev);
+ }
return result ? FAILED : SUCCESS;
}
diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c
index 24e2dc3148a4..c05a85bc5925 100644
--- a/drivers/usb/misc/berry_charge.c
+++ b/drivers/usb/misc/berry_charge.c
@@ -123,6 +123,11 @@ static int berry_probe(struct usb_interface *intf,
{
struct usb_device *udev = interface_to_usbdev(intf);
+ if (udev->bus_mA < 500) {
+ dbg(&udev->dev, "Not enough power to charge available\n");
+ return -ENODEV;
+ }
+
dbg(&udev->dev, "Power is set to %dmA\n",
udev->actconfig->desc.bMaxPower * 2);
diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c
index e762beb5f3c6..879a980ca8c4 100644
--- a/drivers/usb/misc/emi26.c
+++ b/drivers/usb/misc/emi26.c
@@ -160,7 +160,7 @@ static int emi26_load_firmware (struct usb_device *dev)
err("%s - error loading firmware: error = %d", __func__, err);
goto wraperr;
}
- } while (i > 0);
+ } while (rec);
/* Assert reset (stop the CPU in the EMI) */
err = emi26_set_reset(dev,1);
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 444c69c447be..5f1a19d1497d 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -192,8 +192,6 @@ static struct urb *simple_alloc_urb (
{
struct urb *urb;
- if (bytes < 0)
- return NULL;
urb = usb_alloc_urb (0, GFP_KERNEL);
if (!urb)
return urb;
diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig
index deb9ddffa402..f28f350cd96a 100644
--- a/drivers/usb/mon/Kconfig
+++ b/drivers/usb/mon/Kconfig
@@ -3,14 +3,13 @@
#
config USB_MON
- bool "USB Monitor"
- depends on USB!=n
- default y
+ tristate "USB Monitor"
+ depends on USB
+ default y if USB=y
+ default m if USB=m
help
- If you say Y here, a component which captures the USB traffic
+ If you select this option, a component which captures the USB traffic
between peripheral-specific drivers and HC drivers will be built.
For more information, see <file:Documentation/usb/usbmon.txt>.
- This is somewhat experimental at this time, but it should be safe.
-
- If unsure, say Y.
+ If unsure, say Y (if allowed), otherwise M.
diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile
index 0f76ed5e1617..c6516b566731 100644
--- a/drivers/usb/mon/Makefile
+++ b/drivers/usb/mon/Makefile
@@ -4,5 +4,4 @@
usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o
-# This does not use CONFIG_USB_MON because we want this to use a tristate.
-obj-$(CONFIG_USB) += usbmon.o
+obj-$(CONFIG_USB_MON) += usbmon.o
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 4b9542bbb35c..5af7379cd9a3 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -11,7 +11,7 @@ config USB_MUSB_HDRC
depends on (USB || USB_GADGET) && HAVE_CLK
depends on !SUPERH
select TWL4030_USB if MACH_OMAP_3430SDP
- tristate 'Inventra Highspeed Dual Role Controller (TI, ...)'
+ tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
help
Say Y here if your system has a dual role high speed USB
controller based on the Mentor Graphics silicon IP. Then
@@ -22,6 +22,9 @@ config USB_MUSB_HDRC
Texas Instruments parts using this IP include DaVinci 644x,
OMAP 243x, OMAP 343x, and TUSB 6010.
+ Analog Devices parts using this IP include Blackfin BF54x,
+ BF525 and BF527.
+
If you do not know what this is, please say N.
To compile this driver as a module, choose M here; the
@@ -33,6 +36,8 @@ config USB_MUSB_SOC
default y if ARCH_DAVINCI
default y if ARCH_OMAP2430
default y if ARCH_OMAP34XX
+ default y if (BF54x && !BF544)
+ default y if (BF52x && !BF522 && !BF523)
comment "DaVinci 644x USB support"
depends on USB_MUSB_HDRC && ARCH_DAVINCI
@@ -43,6 +48,9 @@ comment "OMAP 243x high speed USB support"
comment "OMAP 343x high speed USB support"
depends on USB_MUSB_HDRC && ARCH_OMAP34XX
+comment "Blackfin high speed USB Support"
+ depends on USB_MUSB_HDRC && (BF54x && !BF544) || (BF52x && !BF522 && !BF523)
+
config USB_TUSB6010
boolean "TUSB 6010 support"
depends on USB_MUSB_HDRC && !USB_MUSB_SOC
@@ -142,7 +150,7 @@ config MUSB_PIO_ONLY
config USB_INVENTRA_DMA
bool
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
- default ARCH_OMAP2430 || ARCH_OMAP34XX
+ default ARCH_OMAP2430 || ARCH_OMAP34XX || BLACKFIN
help
Enable DMA transfers using Mentor's engine.
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index b6af0d687a73..85710ccc1887 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -22,6 +22,14 @@ ifeq ($(CONFIG_ARCH_OMAP3430),y)
musb_hdrc-objs += omap2430.o
endif
+ifeq ($(CONFIG_BF54x),y)
+ musb_hdrc-objs += blackfin.o
+endif
+
+ifeq ($(CONFIG_BF52x),y)
+ musb_hdrc-objs += blackfin.o
+endif
+
ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y)
musb_hdrc-objs += musb_gadget_ep0.o musb_gadget.o
endif
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
new file mode 100644
index 000000000000..786134852092
--- /dev/null
+++ b/drivers/usb/musb/blackfin.c
@@ -0,0 +1,320 @@
+/*
+ * MUSB OTG controller driver for Blackfin Processors
+ *
+ * Copyright 2006-2008 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <asm/cacheflush.h>
+
+#include "musb_core.h"
+#include "blackfin.h"
+
+/*
+ * Load an endpoint's FIFO
+ */
+void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
+{
+ void __iomem *fifo = hw_ep->fifo;
+ void __iomem *epio = hw_ep->regs;
+
+ prefetch((u8 *)src);
+
+ musb_writew(epio, MUSB_TXCOUNT, len);
+
+ DBG(4, "TX ep%d fifo %p count %d buf %p, epio %p\n",
+ hw_ep->epnum, fifo, len, src, epio);
+
+ dump_fifo_data(src, len);
+
+ if (unlikely((unsigned long)src & 0x01))
+ outsw_8((unsigned long)fifo, src,
+ len & 0x01 ? (len >> 1) + 1 : len >> 1);
+ else
+ outsw((unsigned long)fifo, src,
+ len & 0x01 ? (len >> 1) + 1 : len >> 1);
+}
+
+/*
+ * Unload an endpoint's FIFO
+ */
+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
+{
+ void __iomem *fifo = hw_ep->fifo;
+ u8 epnum = hw_ep->epnum;
+ u16 dma_reg = 0;
+
+ DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
+ 'R', hw_ep->epnum, fifo, len, dst);
+
+#ifdef CONFIG_BF52x
+ invalidate_dcache_range((unsigned int)dst,
+ (unsigned int)(dst + len));
+
+ /* Setup DMA address register */
+ dma_reg = (u16) ((u32) dst & 0xFFFF);
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
+ SSYNC();
+
+ dma_reg = (u16) (((u32) dst >> 16) & 0xFFFF);
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
+ SSYNC();
+
+ /* Setup DMA count register */
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len);
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0);
+ SSYNC();
+
+ /* Enable the DMA */
+ dma_reg = (epnum << 4) | DMA_ENA | INT_ENA;
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);
+ SSYNC();
+
+ /* Wait for compelete */
+ while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))
+ cpu_relax();
+
+ /* acknowledge dma interrupt */
+ bfin_write_USB_DMA_INTERRUPT(1 << epnum);
+ SSYNC();
+
+ /* Reset DMA */
+ bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0);
+ SSYNC();
+#else
+ if (unlikely((unsigned long)dst & 0x01))
+ insw_8((unsigned long)fifo, dst,
+ len & 0x01 ? (len >> 1) + 1 : len >> 1);
+ else
+ insw((unsigned long)fifo, dst,
+ len & 0x01 ? (len >> 1) + 1 : len >> 1);
+#endif
+
+ dump_fifo_data(dst, len);
+}
+
+static irqreturn_t blackfin_interrupt(int irq, void *__hci)
+{
+ unsigned long flags;
+ irqreturn_t retval = IRQ_NONE;
+ struct musb *musb = __hci;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
+ musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
+ musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
+
+ if (musb->int_usb || musb->int_tx || musb->int_rx) {
+ musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
+ musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
+ musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
+ retval = musb_interrupt(musb);
+ }
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ /* REVISIT we sometimes get spurious IRQs on g_ep0
+ * not clear why... fall in BF54x too.
+ */
+ if (retval != IRQ_HANDLED)
+ DBG(5, "spurious?\n");
+
+ return IRQ_HANDLED;
+}
+
+static void musb_conn_timer_handler(unsigned long _musb)
+{
+ struct musb *musb = (void *)_musb;
+ unsigned long flags;
+ u16 val;
+
+ spin_lock_irqsave(&musb->lock, flags);
+ switch (musb->xceiv.state) {
+ case OTG_STATE_A_IDLE:
+ case OTG_STATE_A_WAIT_BCON:
+ /* Start a new session */
+ val = musb_readw(musb->mregs, MUSB_DEVCTL);
+ val |= MUSB_DEVCTL_SESSION;
+ musb_writew(musb->mregs, MUSB_DEVCTL, val);
+
+ val = musb_readw(musb->mregs, MUSB_DEVCTL);
+ if (!(val & MUSB_DEVCTL_BDEVICE)) {
+ gpio_set_value(musb->config->gpio_vrsel, 1);
+ musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+ } else {
+ gpio_set_value(musb->config->gpio_vrsel, 0);
+
+ /* Ignore VBUSERROR and SUSPEND IRQ */
+ val = musb_readb(musb->mregs, MUSB_INTRUSBE);
+ val &= ~MUSB_INTR_VBUSERROR;
+ musb_writeb(musb->mregs, MUSB_INTRUSBE, val);
+
+ val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
+ musb_writeb(musb->mregs, MUSB_INTRUSB, val);
+
+ val = MUSB_POWER_HSENAB;
+ musb_writeb(musb->mregs, MUSB_POWER, val);
+ }
+ mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
+ break;
+
+ default:
+ DBG(1, "%s state not handled\n", otg_state_string(musb));
+ break;
+ }
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ DBG(4, "state is %s\n", otg_state_string(musb));
+}
+
+void musb_platform_enable(struct musb *musb)
+{
+ if (is_host_enabled(musb)) {
+ mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
+ musb->a_wait_bcon = TIMER_DELAY;
+ }
+}
+
+void musb_platform_disable(struct musb *musb)
+{
+}
+
+static void bfin_vbus_power(struct musb *musb, int is_on, int sleeping)
+{
+}
+
+static void bfin_set_vbus(struct musb *musb, int is_on)
+{
+ if (is_on)
+ gpio_set_value(musb->config->gpio_vrsel, 1);
+ else
+ gpio_set_value(musb->config->gpio_vrsel, 0);
+
+ DBG(1, "VBUS %s, devctl %02x "
+ /* otg %3x conf %08x prcm %08x */ "\n",
+ otg_state_string(musb),
+ musb_readb(musb->mregs, MUSB_DEVCTL));
+}
+
+static int bfin_set_power(struct otg_transceiver *x, unsigned mA)
+{
+ return 0;
+}
+
+void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
+{
+ if (is_host_enabled(musb))
+ mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
+}
+
+int musb_platform_get_vbus_status(struct musb *musb)
+{
+ return 0;
+}
+
+void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+{
+}
+
+int __init musb_platform_init(struct musb *musb)
+{
+
+ /*
+ * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
+ * and OTG HOST modes, while rev 1.1 and greater require PE7 to
+ * be low for DEVICE mode and high for HOST mode. We set it high
+ * here because we are in host mode
+ */
+
+ if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
+ printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d \n",
+ musb->config->gpio_vrsel);
+ return -ENODEV;
+ }
+ gpio_direction_output(musb->config->gpio_vrsel, 0);
+
+ if (ANOMALY_05000346) {
+ bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
+ SSYNC();
+ }
+
+ if (ANOMALY_05000347) {
+ bfin_write_USB_APHY_CNTRL(0x0);
+ SSYNC();
+ }
+
+ /* TODO
+ * Set SIC-IVG register
+ */
+
+ /* Configure PLL oscillator register */
+ bfin_write_USB_PLLOSC_CTRL(0x30a8);
+ SSYNC();
+
+ bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1);
+ SSYNC();
+
+ bfin_write_USB_EP_NI0_RXMAXP(64);
+ SSYNC();
+
+ bfin_write_USB_EP_NI0_TXMAXP(64);
+ SSYNC();
+
+ /* Route INTRUSB/INTR_RX/INTR_TX to USB_INT0*/
+ bfin_write_USB_GLOBINTR(0x7);
+ SSYNC();
+
+ bfin_write_USB_GLOBAL_CTL(GLOBAL_ENA | EP1_TX_ENA | EP2_TX_ENA |
+ EP3_TX_ENA | EP4_TX_ENA | EP5_TX_ENA |
+ EP6_TX_ENA | EP7_TX_ENA | EP1_RX_ENA |
+ EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA |
+ EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA);
+ SSYNC();
+
+ if (is_host_enabled(musb)) {
+ musb->board_set_vbus = bfin_set_vbus;
+ setup_timer(&musb_conn_timer,
+ musb_conn_timer_handler, (unsigned long) musb);
+ }
+ if (is_peripheral_enabled(musb))
+ musb->xceiv.set_power = bfin_set_power;
+
+ musb->isr = blackfin_interrupt;
+
+ return 0;
+}
+
+int musb_platform_suspend(struct musb *musb)
+{
+ return 0;
+}
+
+int musb_platform_resume(struct musb *musb)
+{
+ return 0;
+}
+
+
+int musb_platform_exit(struct musb *musb)
+{
+
+ bfin_vbus_power(musb, 0 /*off*/, 1);
+ gpio_free(musb->config->gpio_vrsel);
+ musb_platform_suspend(musb);
+
+ return 0;
+}
diff --git a/drivers/usb/musb/blackfin.h b/drivers/usb/musb/blackfin.h
new file mode 100644
index 000000000000..a240c1e53d16
--- /dev/null
+++ b/drivers/usb/musb/blackfin.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2007 by Analog Devices, Inc.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ */
+
+#ifndef __MUSB_BLACKFIN_H__
+#define __MUSB_BLACKFIN_H__
+
+/*
+ * Blackfin specific definitions
+ */
+
+#undef DUMP_FIFO_DATA
+#ifdef DUMP_FIFO_DATA
+static void dump_fifo_data(u8 *buf, u16 len)
+{
+ u8 *tmp = buf;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (!(i % 16) && i)
+ pr_debug("\n");
+ pr_debug("%02x ", *tmp++);
+ }
+ pr_debug("\n");
+}
+#else
+#define dump_fifo_data(buf, len) do {} while (0)
+#endif
+
+#ifdef CONFIG_BF52x
+
+#define USB_DMA_BASE USB_DMA_INTERRUPT
+#define USB_DMAx_CTRL 0x04
+#define USB_DMAx_ADDR_LOW 0x08
+#define USB_DMAx_ADDR_HIGH 0x0C
+#define USB_DMAx_COUNT_LOW 0x10
+#define USB_DMAx_COUNT_HIGH 0x14
+
+#define USB_DMA_REG(ep, reg) (USB_DMA_BASE + 0x20 * ep + reg)
+#endif
+
+/* Almost 1 second */
+#define TIMER_DELAY (1 * HZ)
+
+static struct timer_list musb_conn_timer;
+
+#endif /* __MUSB_BLACKFIN_H__ */
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index dfb3bcbe00fc..0d566dc5ce06 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -32,9 +32,9 @@
#include <linux/io.h>
#include <linux/gpio.h>
-#include <asm/arch/hardware.h>
-#include <asm/arch/memory.h>
-#include <asm/arch/gpio.h>
+#include <mach/arch/hardware.h>
+#include <mach/arch/memory.h>
+#include <mach/arch/gpio.h>
#include <asm/mach-types.h>
#include "musb_core.h"
@@ -364,6 +364,18 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
return IRQ_HANDLED;
}
+int musb_platform_set_mode(struct musb *musb, u8 mode)
+{
+ /* EVM can't do this (right?) */
+ return -EIO;
+}
+
+int musb_platform_set_mode(struct musb *musb, u8 mode)
+{
+ /* EVM can't do this (right?) */
+ return -EIO;
+}
+
int __init musb_platform_init(struct musb *musb)
{
void __iomem *tibase = musb->ctrl_base;
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 5280dba9b1fb..6c7faacfb535 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -148,7 +148,8 @@ static inline struct musb *dev_to_musb(struct device *dev)
/*-------------------------------------------------------------------------*/
-#ifndef CONFIG_USB_TUSB6010
+#if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN)
+
/*
* Load an endpoint's FIFO
*/
@@ -1124,25 +1125,25 @@ fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep,
#endif
switch (cfg->style) {
case FIFO_TX:
- musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
- musb_writew(mbase, MUSB_TXFIFOADD, c_off);
+ musb_write_txfifosz(mbase, c_size);
+ musb_write_txfifoadd(mbase, c_off);
hw_ep->tx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB);
hw_ep->max_packet_sz_tx = maxpacket;
break;
case FIFO_RX:
- musb_writeb(mbase, MUSB_RXFIFOSZ, c_size);
- musb_writew(mbase, MUSB_RXFIFOADD, c_off);
+ musb_write_rxfifosz(mbase, c_size);
+ musb_write_rxfifoadd(mbase, c_off);
hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB);
hw_ep->max_packet_sz_rx = maxpacket;
break;
case FIFO_RXTX:
- musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
- musb_writew(mbase, MUSB_TXFIFOADD, c_off);
+ musb_write_txfifosz(mbase, c_size);
+ musb_write_txfifoadd(mbase, c_off);
hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB);
hw_ep->max_packet_sz_rx = maxpacket;
- musb_writeb(mbase, MUSB_RXFIFOSZ, c_size);
- musb_writew(mbase, MUSB_RXFIFOADD, c_off);
+ musb_write_rxfifosz(mbase, c_size);
+ musb_write_rxfifoadd(mbase, c_off);
hw_ep->tx_double_buffered = hw_ep->rx_double_buffered;
hw_ep->max_packet_sz_tx = maxpacket;
@@ -1212,7 +1213,7 @@ static int __init ep_config_from_table(struct musb *musb)
if (epn >= musb->config->num_eps) {
pr_debug("%s: invalid ep %d\n",
musb_driver_name, epn);
- continue;
+ return -EINVAL;
}
offset = fifo_setup(musb, hw_ep + epn, cfg++, offset);
if (offset < 0) {
@@ -1246,9 +1247,10 @@ static int __init ep_config_from_table(struct musb *musb)
*/
static int __init ep_config_from_hw(struct musb *musb)
{
- u8 epnum = 0, reg;
+ u8 epnum = 0;
struct musb_hw_ep *hw_ep;
void *mbase = musb->mregs;
+ int ret = 0;
DBG(2, "<== static silicon ep config\n");
@@ -1258,26 +1260,9 @@ static int __init ep_config_from_hw(struct musb *musb)
musb_ep_select(mbase, epnum);
hw_ep = musb->endpoints + epnum;
- /* read from core using indexed model */
- reg = musb_readb(hw_ep->regs, 0x10 + MUSB_FIFOSIZE);
- if (!reg) {
- /* 0's returned when no more endpoints */
+ ret = musb_read_fifosize(musb, hw_ep, epnum);
+ if (ret < 0)
break;
- }
- musb->nr_endpoints++;
- musb->epmask |= (1 << epnum);
-
- hw_ep->max_packet_sz_tx = 1 << (reg & 0x0f);
-
- /* shared TX/RX FIFO? */
- if ((reg & 0xf0) == 0xf0) {
- hw_ep->max_packet_sz_rx = hw_ep->max_packet_sz_tx;
- hw_ep->is_shared_fifo = true;
- continue;
- } else {
- hw_ep->max_packet_sz_rx = 1 << ((reg & 0xf0) >> 4);
- hw_ep->is_shared_fifo = false;
- }
/* FIXME set up hw_ep->{rx,tx}_double_buffered */
@@ -1326,7 +1311,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
/* log core options (read using indexed model) */
musb_ep_select(mbase, 0);
- reg = musb_readb(mbase, 0x10 + MUSB_CONFIGDATA);
+ reg = musb_read_configdata(mbase);
strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8");
if (reg & MUSB_CONFIGDATA_DYNFIFO)
@@ -1391,7 +1376,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
}
/* log release info */
- hwvers = musb_readw(mbase, MUSB_HWVERS);
+ hwvers = musb_read_hwvers(mbase);
rev_major = (hwvers >> 10) & 0x1f;
rev_minor = hwvers & 0x3ff;
snprintf(aRevision, 32, "%d.%d%s", rev_major,
@@ -1400,8 +1385,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
musb_driver_name, type, aRevision, aDate);
/* configure ep0 */
- musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE;
- musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE;
+ musb_configure_ep0(musb);
/* discover endpoint configuration */
musb->nr_endpoints = 1;
@@ -1445,7 +1429,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase;
#ifdef CONFIG_USB_MUSB_HDRC_HCD
- hw_ep->target_regs = MUSB_BUSCTL_OFFSET(i, 0) + mbase;
+ hw_ep->target_regs = musb_read_target_reg_base(i, mbase);
hw_ep->rx_reinit = 1;
hw_ep->tx_reinit = 1;
#endif
@@ -1671,17 +1655,20 @@ musb_mode_store(struct device *dev, struct device_attribute *attr,
{
struct musb *musb = dev_to_musb(dev);
unsigned long flags;
+ int status;
spin_lock_irqsave(&musb->lock, flags);
- if (!strncmp(buf, "host", 4))
- musb_platform_set_mode(musb, MUSB_HOST);
- if (!strncmp(buf, "peripheral", 10))
- musb_platform_set_mode(musb, MUSB_PERIPHERAL);
- if (!strncmp(buf, "otg", 3))
- musb_platform_set_mode(musb, MUSB_OTG);
+ if (sysfs_streq(buf, "host"))
+ status = musb_platform_set_mode(musb, MUSB_HOST);
+ else if (sysfs_streq(buf, "peripheral"))
+ status = musb_platform_set_mode(musb, MUSB_PERIPHERAL);
+ else if (sysfs_streq(buf, "otg"))
+ status = musb_platform_set_mode(musb, MUSB_OTG);
+ else
+ status = -EINVAL;
spin_unlock_irqrestore(&musb->lock, flags);
- return n;
+ return (status == 0) ? n : status;
}
static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store);
@@ -1781,7 +1768,7 @@ allocate_instance(struct device *dev,
#ifdef CONFIG_USB_MUSB_HDRC_HCD
struct usb_hcd *hcd;
- hcd = usb_create_hcd(&musb_hc_driver, dev, dev->bus_id);
+ hcd = usb_create_hcd(&musb_hc_driver, dev, dev_name(dev));
if (!hcd)
return NULL;
/* usbcore sets dev->driver_data to hcd, and sometimes uses that... */
@@ -1810,7 +1797,6 @@ allocate_instance(struct device *dev,
for (epnum = 0, ep = musb->endpoints;
epnum < musb->config->num_eps;
epnum++, ep++) {
-
ep->musb = musb;
ep->epnum = epnum;
}
@@ -1838,7 +1824,7 @@ static void musb_free(struct musb *musb)
musb_gadget_cleanup(musb);
#endif
- if (musb->nIrq >= 0) {
+ if (musb->nIrq >= 0 && musb->irq_wake) {
disable_irq_wake(musb->nIrq);
free_irq(musb->nIrq, musb);
}
@@ -1984,15 +1970,19 @@ bad_config:
INIT_WORK(&musb->irq_work, musb_irq_work);
/* attach to the IRQ */
- if (request_irq(nIrq, musb->isr, 0, dev->bus_id, musb)) {
+ if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) {
dev_err(dev, "request_irq %d failed!\n", nIrq);
status = -ENODEV;
goto fail2;
}
musb->nIrq = nIrq;
/* FIXME this handles wakeup irqs wrong */
- if (enable_irq_wake(nIrq) == 0)
+ if (enable_irq_wake(nIrq) == 0) {
+ musb->irq_wake = 1;
device_init_wakeup(dev, 1);
+ } else {
+ musb->irq_wake = 0;
+ }
pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n",
musb_driver_name,
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 82227251931b..630946a2d9fc 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -191,7 +191,7 @@ enum musb_g_ep0_state {
*/
#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_ARCH_OMAP2430) \
- || defined(CONFIG_ARCH_OMAP3430)
+ || defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_BLACKFIN)
/* REVISIT indexed access seemed to
* misbehave (on DaVinci) for at least peripheral IN ...
*/
@@ -359,6 +359,7 @@ struct musb {
struct otg_transceiver xceiv;
int nIrq;
+ unsigned irq_wake:1;
struct musb_hw_ep endpoints[MUSB_C_NUM_EPS];
#define control_ep endpoints
@@ -447,6 +448,70 @@ static inline struct musb *gadget_to_musb(struct usb_gadget *g)
}
#endif
+#ifdef CONFIG_BLACKFIN
+static inline int musb_read_fifosize(struct musb *musb,
+ struct musb_hw_ep *hw_ep, u8 epnum)
+{
+ musb->nr_endpoints++;
+ musb->epmask |= (1 << epnum);
+
+ if (epnum < 5) {
+ hw_ep->max_packet_sz_tx = 128;
+ hw_ep->max_packet_sz_rx = 128;
+ } else {
+ hw_ep->max_packet_sz_tx = 1024;
+ hw_ep->max_packet_sz_rx = 1024;
+ }
+ hw_ep->is_shared_fifo = false;
+
+ return 0;
+}
+
+static inline void musb_configure_ep0(struct musb *musb)
+{
+ musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE;
+ musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE;
+ musb->endpoints[0].is_shared_fifo = true;
+}
+
+#else
+
+static inline int musb_read_fifosize(struct musb *musb,
+ struct musb_hw_ep *hw_ep, u8 epnum)
+{
+ u8 reg = 0;
+
+ /* read from core using indexed model */
+ reg = musb_readb(hw_ep->regs, 0x10 + MUSB_FIFOSIZE);
+ /* 0's returned when no more endpoints */
+ if (!reg)
+ return -ENODEV;
+
+ musb->nr_endpoints++;
+ musb->epmask |= (1 << epnum);
+
+ hw_ep->max_packet_sz_tx = 1 << (reg & 0x0f);
+
+ /* shared TX/RX FIFO? */
+ if ((reg & 0xf0) == 0xf0) {
+ hw_ep->max_packet_sz_rx = hw_ep->max_packet_sz_tx;
+ hw_ep->is_shared_fifo = true;
+ return 0;
+ } else {
+ hw_ep->max_packet_sz_rx = 1 << ((reg & 0xf0) >> 4);
+ hw_ep->is_shared_fifo = false;
+ }
+
+ return 0;
+}
+
+static inline void musb_configure_ep0(struct musb *musb)
+{
+ musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE;
+ musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE;
+}
+#endif /* CONFIG_BLACKFIN */
+
/***************************** Glue it together *****************************/
@@ -467,16 +532,16 @@ extern void musb_platform_disable(struct musb *musb);
extern void musb_hnp_stop(struct musb *musb);
-extern void musb_platform_set_mode(struct musb *musb, u8 musb_mode);
+extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode);
-#if defined(CONFIG_USB_TUSB6010) || \
+#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) || \
defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout);
#else
#define musb_platform_try_idle(x, y) do {} while (0)
#endif
-#ifdef CONFIG_USB_TUSB6010
+#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN)
extern int musb_platform_get_vbus_status(struct musb *musb);
#else
#define musb_platform_get_vbus_status(x) 0
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index d6a802c224fa..6197daeab8f9 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1633,7 +1633,7 @@ int __init musb_gadget_setup(struct musb *musb)
musb->g.speed = USB_SPEED_UNKNOWN;
/* this "gadget" abstracts/virtualizes the controller */
- strcpy(musb->g.dev.bus_id, "gadget");
+ dev_set_name(&musb->g.dev, "gadget");
musb->g.dev.parent = musb->controller;
musb->g.dev.dma_mask = musb->controller->dma_mask;
musb->g.dev.release = musb_gadget_release;
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index cc64462d4c4e..99fa61234876 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -112,18 +112,21 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
{
void __iomem *epio = ep->regs;
u16 csr;
+ u16 lastcsr = 0;
int retries = 1000;
csr = musb_readw(epio, MUSB_TXCSR);
while (csr & MUSB_TXCSR_FIFONOTEMPTY) {
- DBG(5, "Host TX FIFONOTEMPTY csr: %02x\n", csr);
+ if (csr != lastcsr)
+ DBG(3, "Host TX FIFONOTEMPTY csr: %02x\n", csr);
+ lastcsr = csr;
csr |= MUSB_TXCSR_FLUSHFIFO;
musb_writew(epio, MUSB_TXCSR, csr);
csr = musb_readw(epio, MUSB_TXCSR);
- if (retries-- < 1) {
- ERR("Could not flush host TX fifo: csr: %04x\n", csr);
+ if (WARN(retries-- < 1,
+ "Could not flush host TX%d fifo: csr: %04x\n",
+ ep->epnum, csr))
return;
- }
mdelay(1);
}
}
@@ -268,7 +271,7 @@ __musb_giveback(struct musb *musb, struct urb *urb, int status)
__releases(musb->lock)
__acquires(musb->lock)
{
- DBG(({ int level; switch (urb->status) {
+ DBG(({ int level; switch (status) {
case 0:
level = 4;
break;
@@ -283,8 +286,8 @@ __acquires(musb->lock)
level = 2;
break;
}; level; }),
- "complete %p (%d), dev%d ep%d%s, %d/%d\n",
- urb, urb->status,
+ "complete %p %pF (%d), dev%d ep%d%s, %d/%d\n",
+ urb, urb->complete, status,
usb_pipedevice(urb->pipe),
usb_pipeendpoint(urb->pipe),
usb_pipein(urb->pipe) ? "in" : "out",
@@ -593,12 +596,10 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
/* target addr and (for multipoint) hub addr/port */
if (musb->is_multipoint) {
- musb_writeb(ep->target_regs, MUSB_RXFUNCADDR,
- qh->addr_reg);
- musb_writeb(ep->target_regs, MUSB_RXHUBADDR,
- qh->h_addr_reg);
- musb_writeb(ep->target_regs, MUSB_RXHUBPORT,
- qh->h_port_reg);
+ musb_write_rxfunaddr(ep->target_regs, qh->addr_reg);
+ musb_write_rxhubaddr(ep->target_regs, qh->h_addr_reg);
+ musb_write_rxhubport(ep->target_regs, qh->h_port_reg);
+
} else
musb_writeb(musb->mregs, MUSB_FADDR, qh->addr_reg);
@@ -712,15 +713,9 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
/* target addr and (for multipoint) hub addr/port */
if (musb->is_multipoint) {
- musb_writeb(mbase,
- MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR),
- qh->addr_reg);
- musb_writeb(mbase,
- MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR),
- qh->h_addr_reg);
- musb_writeb(mbase,
- MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT),
- qh->h_port_reg);
+ musb_write_txfunaddr(mbase, epnum, qh->addr_reg);
+ musb_write_txhubaddr(mbase, epnum, qh->h_addr_reg);
+ musb_write_txhubport(mbase, epnum, qh->h_port_reg);
/* FIXME if !epnum, do the same for RX ... */
} else
musb_writeb(mbase, MUSB_FADDR, qh->addr_reg);
@@ -988,8 +983,10 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
if (fifo_count) {
fifo_dest = (u8 *) (urb->transfer_buffer
+ urb->actual_length);
- DBG(3, "Sending %d bytes to %p\n",
- fifo_count, fifo_dest);
+ DBG(3, "Sending %d byte%s to ep0 fifo %p\n",
+ fifo_count,
+ (fifo_count == 1) ? "" : "s",
+ fifo_dest);
musb_write_fifo(hw_ep, fifo_count, fifo_dest);
urb->actual_length += fifo_count;
diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h
index 223f0a514094..b06e9ef00cfc 100644
--- a/drivers/usb/musb/musb_io.h
+++ b/drivers/usb/musb/musb_io.h
@@ -39,7 +39,7 @@
#if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \
&& !defined(CONFIG_AVR32) && !defined(CONFIG_PPC32) \
- && !defined(CONFIG_PPC64)
+ && !defined(CONFIG_PPC64) && !defined(CONFIG_BLACKFIN)
static inline void readsl(const void __iomem *addr, void *buf, int len)
{ insl((unsigned long)addr, buf, len); }
static inline void readsw(const void __iomem *addr, void *buf, int len)
@@ -56,6 +56,8 @@ static inline void writesb(const void __iomem *addr, const void *buf, int len)
#endif
+#ifndef CONFIG_BLACKFIN
+
/* NOTE: these offsets are all in bytes */
static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
@@ -114,4 +116,26 @@ static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
#endif /* CONFIG_USB_TUSB6010 */
+#else
+
+static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
+ { return (u8) (bfin_read16(addr + offset)); }
+
+static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
+ { return bfin_read16(addr + offset); }
+
+static inline u32 musb_readl(const void __iomem *addr, unsigned offset)
+ { return (u32) (bfin_read16(addr + offset)); }
+
+static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
+ { bfin_write16(addr + offset, (u16) data); }
+
+static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
+ { bfin_write16(addr + offset, data); }
+
+static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
+ { bfin_write16(addr + offset, (u16) data); }
+
+#endif /* CONFIG_BLACKFIN */
+
#endif
diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h
index 9c228661aa5a..de3b2f18db44 100644
--- a/drivers/usb/musb/musb_regs.h
+++ b/drivers/usb/musb/musb_regs.h
@@ -38,97 +38,6 @@
#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */
/*
- * Common USB registers
- */
-
-#define MUSB_FADDR 0x00 /* 8-bit */
-#define MUSB_POWER 0x01 /* 8-bit */
-
-#define MUSB_INTRTX 0x02 /* 16-bit */
-#define MUSB_INTRRX 0x04
-#define MUSB_INTRTXE 0x06
-#define MUSB_INTRRXE 0x08
-#define MUSB_INTRUSB 0x0A /* 8 bit */
-#define MUSB_INTRUSBE 0x0B /* 8 bit */
-#define MUSB_FRAME 0x0C
-#define MUSB_INDEX 0x0E /* 8 bit */
-#define MUSB_TESTMODE 0x0F /* 8 bit */
-
-/* Get offset for a given FIFO from musb->mregs */
-#ifdef CONFIG_USB_TUSB6010
-#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20))
-#else
-#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4))
-#endif
-
-/*
- * Additional Control Registers
- */
-
-#define MUSB_DEVCTL 0x60 /* 8 bit */
-
-/* These are always controlled through the INDEX register */
-#define MUSB_TXFIFOSZ 0x62 /* 8-bit (see masks) */
-#define MUSB_RXFIFOSZ 0x63 /* 8-bit (see masks) */
-#define MUSB_TXFIFOADD 0x64 /* 16-bit offset shifted right 3 */
-#define MUSB_RXFIFOADD 0x66 /* 16-bit offset shifted right 3 */
-
-/* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */
-#define MUSB_HWVERS 0x6C /* 8 bit */
-
-#define MUSB_EPINFO 0x78 /* 8 bit */
-#define MUSB_RAMINFO 0x79 /* 8 bit */
-#define MUSB_LINKINFO 0x7a /* 8 bit */
-#define MUSB_VPLEN 0x7b /* 8 bit */
-#define MUSB_HS_EOF1 0x7c /* 8 bit */
-#define MUSB_FS_EOF1 0x7d /* 8 bit */
-#define MUSB_LS_EOF1 0x7e /* 8 bit */
-
-/* Offsets to endpoint registers */
-#define MUSB_TXMAXP 0x00
-#define MUSB_TXCSR 0x02
-#define MUSB_CSR0 MUSB_TXCSR /* Re-used for EP0 */
-#define MUSB_RXMAXP 0x04
-#define MUSB_RXCSR 0x06
-#define MUSB_RXCOUNT 0x08
-#define MUSB_COUNT0 MUSB_RXCOUNT /* Re-used for EP0 */
-#define MUSB_TXTYPE 0x0A
-#define MUSB_TYPE0 MUSB_TXTYPE /* Re-used for EP0 */
-#define MUSB_TXINTERVAL 0x0B
-#define MUSB_NAKLIMIT0 MUSB_TXINTERVAL /* Re-used for EP0 */
-#define MUSB_RXTYPE 0x0C
-#define MUSB_RXINTERVAL 0x0D
-#define MUSB_FIFOSIZE 0x0F
-#define MUSB_CONFIGDATA MUSB_FIFOSIZE /* Re-used for EP0 */
-
-/* Offsets to endpoint registers in indexed model (using INDEX register) */
-#define MUSB_INDEXED_OFFSET(_epnum, _offset) \
- (0x10 + (_offset))
-
-/* Offsets to endpoint registers in flat models */
-#define MUSB_FLAT_OFFSET(_epnum, _offset) \
- (0x100 + (0x10*(_epnum)) + (_offset))
-
-#ifdef CONFIG_USB_TUSB6010
-/* TUSB6010 EP0 configuration register is special */
-#define MUSB_TUSB_OFFSET(_epnum, _offset) \
- (0x10 + _offset)
-#include "tusb6010.h" /* Needed "only" for TUSB_EP0_CONF */
-#endif
-
-/* "bus control"/target registers, for host side multipoint (external hubs) */
-#define MUSB_TXFUNCADDR 0x00
-#define MUSB_TXHUBADDR 0x02
-#define MUSB_TXHUBPORT 0x03
-
-#define MUSB_RXFUNCADDR 0x04
-#define MUSB_RXHUBADDR 0x06
-#define MUSB_RXHUBPORT 0x07
-
-#define MUSB_BUSCTL_OFFSET(_epnum, _offset) \
- (0x80 + (8*(_epnum)) + (_offset))
-
-/*
* MUSB Register bits
*/
@@ -228,7 +137,6 @@
/* TXCSR in Peripheral and Host mode */
#define MUSB_TXCSR_AUTOSET 0x8000
-#define MUSB_TXCSR_MODE 0x2000
#define MUSB_TXCSR_DMAENAB 0x1000
#define MUSB_TXCSR_FRCDATATOG 0x0800
#define MUSB_TXCSR_DMAMODE 0x0400
@@ -297,4 +205,309 @@
/* HUBADDR */
#define MUSB_HUBADDR_MULTI_TT 0x80
+
+#ifndef CONFIG_BLACKFIN
+
+/*
+ * Common USB registers
+ */
+
+#define MUSB_FADDR 0x00 /* 8-bit */
+#define MUSB_POWER 0x01 /* 8-bit */
+
+#define MUSB_INTRTX 0x02 /* 16-bit */
+#define MUSB_INTRRX 0x04
+#define MUSB_INTRTXE 0x06
+#define MUSB_INTRRXE 0x08
+#define MUSB_INTRUSB 0x0A /* 8 bit */
+#define MUSB_INTRUSBE 0x0B /* 8 bit */
+#define MUSB_FRAME 0x0C
+#define MUSB_INDEX 0x0E /* 8 bit */
+#define MUSB_TESTMODE 0x0F /* 8 bit */
+
+/* Get offset for a given FIFO from musb->mregs */
+#ifdef CONFIG_USB_TUSB6010
+#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20))
+#else
+#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4))
+#endif
+
+/*
+ * Additional Control Registers
+ */
+
+#define MUSB_DEVCTL 0x60 /* 8 bit */
+
+/* These are always controlled through the INDEX register */
+#define MUSB_TXFIFOSZ 0x62 /* 8-bit (see masks) */
+#define MUSB_RXFIFOSZ 0x63 /* 8-bit (see masks) */
+#define MUSB_TXFIFOADD 0x64 /* 16-bit offset shifted right 3 */
+#define MUSB_RXFIFOADD 0x66 /* 16-bit offset shifted right 3 */
+
+/* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */
+#define MUSB_HWVERS 0x6C /* 8 bit */
+
+#define MUSB_EPINFO 0x78 /* 8 bit */
+#define MUSB_RAMINFO 0x79 /* 8 bit */
+#define MUSB_LINKINFO 0x7a /* 8 bit */
+#define MUSB_VPLEN 0x7b /* 8 bit */
+#define MUSB_HS_EOF1 0x7c /* 8 bit */
+#define MUSB_FS_EOF1 0x7d /* 8 bit */
+#define MUSB_LS_EOF1 0x7e /* 8 bit */
+
+/* Offsets to endpoint registers */
+#define MUSB_TXMAXP 0x00
+#define MUSB_TXCSR 0x02
+#define MUSB_CSR0 MUSB_TXCSR /* Re-used for EP0 */
+#define MUSB_RXMAXP 0x04
+#define MUSB_RXCSR 0x06
+#define MUSB_RXCOUNT 0x08
+#define MUSB_COUNT0 MUSB_RXCOUNT /* Re-used for EP0 */
+#define MUSB_TXTYPE 0x0A
+#define MUSB_TYPE0 MUSB_TXTYPE /* Re-used for EP0 */
+#define MUSB_TXINTERVAL 0x0B
+#define MUSB_NAKLIMIT0 MUSB_TXINTERVAL /* Re-used for EP0 */
+#define MUSB_RXTYPE 0x0C
+#define MUSB_RXINTERVAL 0x0D
+#define MUSB_FIFOSIZE 0x0F
+#define MUSB_CONFIGDATA MUSB_FIFOSIZE /* Re-used for EP0 */
+
+/* Offsets to endpoint registers in indexed model (using INDEX register) */
+#define MUSB_INDEXED_OFFSET(_epnum, _offset) \
+ (0x10 + (_offset))
+
+/* Offsets to endpoint registers in flat models */
+#define MUSB_FLAT_OFFSET(_epnum, _offset) \
+ (0x100 + (0x10*(_epnum)) + (_offset))
+
+#ifdef CONFIG_USB_TUSB6010
+/* TUSB6010 EP0 configuration register is special */
+#define MUSB_TUSB_OFFSET(_epnum, _offset) \
+ (0x10 + _offset)
+#include "tusb6010.h" /* Needed "only" for TUSB_EP0_CONF */
+#endif
+
+#define MUSB_TXCSR_MODE 0x2000
+
+/* "bus control"/target registers, for host side multipoint (external hubs) */
+#define MUSB_TXFUNCADDR 0x00
+#define MUSB_TXHUBADDR 0x02
+#define MUSB_TXHUBPORT 0x03
+
+#define MUSB_RXFUNCADDR 0x04
+#define MUSB_RXHUBADDR 0x06
+#define MUSB_RXHUBPORT 0x07
+
+#define MUSB_BUSCTL_OFFSET(_epnum, _offset) \
+ (0x80 + (8*(_epnum)) + (_offset))
+
+static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
+{
+ musb_writeb(mbase, MUSB_TXFIFOSZ, c_size);
+}
+
+static inline void musb_write_txfifoadd(void __iomem *mbase, u16 c_off)
+{
+ musb_writew(mbase, MUSB_TXFIFOADD, c_off);
+}
+
+static inline void musb_write_rxfifosz(void __iomem *mbase, u8 c_size)
+{
+ musb_writeb(mbase, MUSB_RXFIFOSZ, c_size);
+}
+
+static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
+{
+ musb_writew(mbase, MUSB_RXFIFOADD, c_off);
+}
+
+static inline u8 musb_read_configdata(void __iomem *mbase)
+{
+ return musb_readb(mbase, 0x10 + MUSB_CONFIGDATA);
+}
+
+static inline u16 musb_read_hwvers(void __iomem *mbase)
+{
+ return musb_readw(mbase, MUSB_HWVERS);
+}
+
+static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
+{
+ return (MUSB_BUSCTL_OFFSET(i, 0) + mbase);
+}
+
+static inline void musb_write_rxfunaddr(void __iomem *ep_target_regs,
+ u8 qh_addr_reg)
+{
+ musb_writeb(ep_target_regs, MUSB_RXFUNCADDR, qh_addr_reg);
+}
+
+static inline void musb_write_rxhubaddr(void __iomem *ep_target_regs,
+ u8 qh_h_addr_reg)
+{
+ musb_writeb(ep_target_regs, MUSB_RXHUBADDR, qh_h_addr_reg);
+}
+
+static inline void musb_write_rxhubport(void __iomem *ep_target_regs,
+ u8 qh_h_port_reg)
+{
+ musb_writeb(ep_target_regs, MUSB_RXHUBPORT, qh_h_port_reg);
+}
+
+static inline void musb_write_txfunaddr(void __iomem *mbase, u8 epnum,
+ u8 qh_addr_reg)
+{
+ musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR),
+ qh_addr_reg);
+}
+
+static inline void musb_write_txhubaddr(void __iomem *mbase, u8 epnum,
+ u8 qh_addr_reg)
+{
+ musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR),
+ qh_addr_reg);
+}
+
+static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
+ u8 qh_h_port_reg)
+{
+ musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT),
+ qh_h_port_reg);
+}
+
+#else /* CONFIG_BLACKFIN */
+
+#define USB_BASE USB_FADDR
+#define USB_OFFSET(reg) (reg - USB_BASE)
+
+/*
+ * Common USB registers
+ */
+#define MUSB_FADDR USB_OFFSET(USB_FADDR) /* 8-bit */
+#define MUSB_POWER USB_OFFSET(USB_POWER) /* 8-bit */
+#define MUSB_INTRTX USB_OFFSET(USB_INTRTX) /* 16-bit */
+#define MUSB_INTRRX USB_OFFSET(USB_INTRRX)
+#define MUSB_INTRTXE USB_OFFSET(USB_INTRTXE)
+#define MUSB_INTRRXE USB_OFFSET(USB_INTRRXE)
+#define MUSB_INTRUSB USB_OFFSET(USB_INTRUSB) /* 8 bit */
+#define MUSB_INTRUSBE USB_OFFSET(USB_INTRUSBE)/* 8 bit */
+#define MUSB_FRAME USB_OFFSET(USB_FRAME)
+#define MUSB_INDEX USB_OFFSET(USB_INDEX) /* 8 bit */
+#define MUSB_TESTMODE USB_OFFSET(USB_TESTMODE)/* 8 bit */
+
+/* Get offset for a given FIFO from musb->mregs */
+#define MUSB_FIFO_OFFSET(epnum) \
+ (USB_OFFSET(USB_EP0_FIFO) + ((epnum) * 8))
+
+/*
+ * Additional Control Registers
+ */
+
+#define MUSB_DEVCTL USB_OFFSET(USB_OTG_DEV_CTL) /* 8 bit */
+
+#define MUSB_LINKINFO USB_OFFSET(USB_LINKINFO)/* 8 bit */
+#define MUSB_VPLEN USB_OFFSET(USB_VPLEN) /* 8 bit */
+#define MUSB_HS_EOF1 USB_OFFSET(USB_HS_EOF1) /* 8 bit */
+#define MUSB_FS_EOF1 USB_OFFSET(USB_FS_EOF1) /* 8 bit */
+#define MUSB_LS_EOF1 USB_OFFSET(USB_LS_EOF1) /* 8 bit */
+
+/* Offsets to endpoint registers */
+#define MUSB_TXMAXP 0x00
+#define MUSB_TXCSR 0x04
+#define MUSB_CSR0 MUSB_TXCSR /* Re-used for EP0 */
+#define MUSB_RXMAXP 0x08
+#define MUSB_RXCSR 0x0C
+#define MUSB_RXCOUNT 0x10
+#define MUSB_COUNT0 MUSB_RXCOUNT /* Re-used for EP0 */
+#define MUSB_TXTYPE 0x14
+#define MUSB_TYPE0 MUSB_TXTYPE /* Re-used for EP0 */
+#define MUSB_TXINTERVAL 0x18
+#define MUSB_NAKLIMIT0 MUSB_TXINTERVAL /* Re-used for EP0 */
+#define MUSB_RXTYPE 0x1C
+#define MUSB_RXINTERVAL 0x20
+#define MUSB_TXCOUNT 0x28
+
+/* Offsets to endpoint registers in indexed model (using INDEX register) */
+#define MUSB_INDEXED_OFFSET(_epnum, _offset) \
+ (0x40 + (_offset))
+
+/* Offsets to endpoint registers in flat models */
+#define MUSB_FLAT_OFFSET(_epnum, _offset) \
+ (USB_OFFSET(USB_EP_NI0_TXMAXP) + (0x40 * (_epnum)) + (_offset))
+
+/* Not implemented - HW has seperate Tx/Rx FIFO */
+#define MUSB_TXCSR_MODE 0x0000
+
+/*
+ * Dummy stub for clk framework, it will be removed
+ * until Blackfin supports clk framework
+ */
+#define clk_get(dev, id) NULL
+#define clk_put(clock) do {} while (0)
+#define clk_enable(clock) do {} while (0)
+#define clk_disable(clock) do {} while (0)
+
+static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
+{
+}
+
+static inline void musb_write_txfifoadd(void __iomem *mbase, u16 c_off)
+{
+}
+
+static inline void musb_write_rxfifosz(void __iomem *mbase, u8 c_size)
+{
+}
+
+static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
+{
+}
+
+static inline u8 musb_read_configdata(void __iomem *mbase)
+{
+ return 0;
+}
+
+static inline u16 musb_read_hwvers(void __iomem *mbase)
+{
+ return 0;
+}
+
+static inline u16 musb_read_target_reg_base(u8 i, void __iomem *mbase)
+{
+ return 0;
+}
+
+static inline void musb_write_rxfunaddr(void __iomem *ep_target_regs,
+ u8 qh_addr_req)
+{
+}
+
+static inline void musb_write_rxhubaddr(void __iomem *ep_target_regs,
+ u8 qh_h_addr_reg)
+{
+}
+
+static inline void musb_write_rxhubport(void __iomem *ep_target_regs,
+ u8 qh_h_port_reg)
+{
+}
+
+static inline void musb_write_txfunaddr(void __iomem *mbase, u8 epnum,
+ u8 qh_addr_reg)
+{
+}
+
+static inline void musb_write_txhubaddr(void __iomem *mbase, u8 epnum,
+ u8 qh_addr_reg)
+{
+}
+
+static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
+ u8 qh_h_port_reg)
+{
+}
+
+#endif /* CONFIG_BLACKFIN */
+
#endif /* __MUSB_REGS_H__ */
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 8c734ef2c1ed..8662e9e159c3 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -34,58 +34,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include "musb_core.h"
-
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
-#include "omap2430.h"
-#endif
-
-#define MUSB_HSDMA_BASE 0x200
-#define MUSB_HSDMA_INTR (MUSB_HSDMA_BASE + 0)
-#define MUSB_HSDMA_CONTROL 0x4
-#define MUSB_HSDMA_ADDRESS 0x8
-#define MUSB_HSDMA_COUNT 0xc
-
-#define MUSB_HSDMA_CHANNEL_OFFSET(_bchannel, _offset) \
- (MUSB_HSDMA_BASE + (_bchannel << 4) + _offset)
-
-/* control register (16-bit): */
-#define MUSB_HSDMA_ENABLE_SHIFT 0
-#define MUSB_HSDMA_TRANSMIT_SHIFT 1
-#define MUSB_HSDMA_MODE1_SHIFT 2
-#define MUSB_HSDMA_IRQENABLE_SHIFT 3
-#define MUSB_HSDMA_ENDPOINT_SHIFT 4
-#define MUSB_HSDMA_BUSERROR_SHIFT 8
-#define MUSB_HSDMA_BURSTMODE_SHIFT 9
-#define MUSB_HSDMA_BURSTMODE (3 << MUSB_HSDMA_BURSTMODE_SHIFT)
-#define MUSB_HSDMA_BURSTMODE_UNSPEC 0
-#define MUSB_HSDMA_BURSTMODE_INCR4 1
-#define MUSB_HSDMA_BURSTMODE_INCR8 2
-#define MUSB_HSDMA_BURSTMODE_INCR16 3
-
-#define MUSB_HSDMA_CHANNELS 8
-
-struct musb_dma_controller;
-
-struct musb_dma_channel {
- struct dma_channel channel;
- struct musb_dma_controller *controller;
- u32 start_addr;
- u32 len;
- u16 max_packet_sz;
- u8 idx;
- u8 epnum;
- u8 transmit;
-};
-
-struct musb_dma_controller {
- struct dma_controller controller;
- struct musb_dma_channel channel[MUSB_HSDMA_CHANNELS];
- void *private_data;
- void __iomem *base;
- u8 channel_count;
- u8 used_channels;
- u8 irq;
-};
+#include "musbhsdma.h"
static int dma_controller_start(struct dma_controller *c)
{
@@ -203,12 +152,8 @@ static void configure_channel(struct dma_channel *channel,
: 0);
/* address/count */
- musb_writel(mbase,
- MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS),
- dma_addr);
- musb_writel(mbase,
- MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT),
- len);
+ musb_write_hsdma_addr(mbase, bchannel, dma_addr);
+ musb_write_hsdma_count(mbase, bchannel, len);
/* control (this should start things) */
musb_writew(mbase,
@@ -279,13 +224,8 @@ static int dma_channel_abort(struct dma_channel *channel)
musb_writew(mbase,
MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL),
0);
- musb_writel(mbase,
- MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS),
- 0);
- musb_writel(mbase,
- MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT),
- 0);
-
+ musb_write_hsdma_addr(mbase, bchannel, 0);
+ musb_write_hsdma_count(mbase, bchannel, 0);
channel->status = MUSB_DMA_STATUS_FREE;
}
@@ -333,10 +273,8 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
} else {
u8 devctl;
- addr = musb_readl(mbase,
- MUSB_HSDMA_CHANNEL_OFFSET(
- bchannel,
- MUSB_HSDMA_ADDRESS));
+ addr = musb_read_hsdma_addr(mbase,
+ bchannel);
channel->actual_len = addr
- musb_channel->start_addr;
@@ -375,6 +313,12 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
}
}
}
+
+#ifdef CONFIG_BLACKFIN
+ /* Clear DMA interrup flags */
+ musb_writeb(mbase, MUSB_HSDMA_INTR, int_hsdma);
+#endif
+
retval = IRQ_HANDLED;
done:
spin_unlock_irqrestore(&musb->lock, flags);
@@ -424,7 +368,7 @@ dma_controller_create(struct musb *musb, void __iomem *base)
controller->controller.channel_abort = dma_channel_abort;
if (request_irq(irq, dma_controller_irq, IRQF_DISABLED,
- musb->controller->bus_id, &controller->controller)) {
+ dev_name(musb->controller), &controller->controller)) {
dev_err(dev, "request_irq %d failed!\n", irq);
dma_controller_destroy(&controller->controller);
diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h
new file mode 100644
index 000000000000..1299d92dc83f
--- /dev/null
+++ b/drivers/usb/musb/musbhsdma.h
@@ -0,0 +1,149 @@
+/*
+ * MUSB OTG driver - support for Mentor's DMA controller
+ *
+ * Copyright 2005 Mentor Graphics Corporation
+ * Copyright (C) 2005-2007 by Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This 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
+ *
+ * THIS SOFTWARE IS PROVIDED "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 AUTHORS 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.
+ *
+ */
+
+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
+#include "omap2430.h"
+#endif
+
+#ifndef CONFIG_BLACKFIN
+
+#define MUSB_HSDMA_BASE 0x200
+#define MUSB_HSDMA_INTR (MUSB_HSDMA_BASE + 0)
+#define MUSB_HSDMA_CONTROL 0x4
+#define MUSB_HSDMA_ADDRESS 0x8
+#define MUSB_HSDMA_COUNT 0xc
+
+#define MUSB_HSDMA_CHANNEL_OFFSET(_bchannel, _offset) \
+ (MUSB_HSDMA_BASE + (_bchannel << 4) + _offset)
+
+#define musb_read_hsdma_addr(mbase, bchannel) \
+ musb_readl(mbase, \
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS))
+
+#define musb_write_hsdma_addr(mbase, bchannel, addr) \
+ musb_writel(mbase, \
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS), \
+ addr)
+
+#define musb_write_hsdma_count(mbase, bchannel, len) \
+ musb_writel(mbase, \
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT), \
+ len)
+#else
+
+#define MUSB_HSDMA_BASE 0x400
+#define MUSB_HSDMA_INTR (MUSB_HSDMA_BASE + 0)
+#define MUSB_HSDMA_CONTROL 0x04
+#define MUSB_HSDMA_ADDR_LOW 0x08
+#define MUSB_HSDMA_ADDR_HIGH 0x0C
+#define MUSB_HSDMA_COUNT_LOW 0x10
+#define MUSB_HSDMA_COUNT_HIGH 0x14
+
+#define MUSB_HSDMA_CHANNEL_OFFSET(_bchannel, _offset) \
+ (MUSB_HSDMA_BASE + (_bchannel * 0x20) + _offset)
+
+static inline u32 musb_read_hsdma_addr(void __iomem *mbase, u8 bchannel)
+{
+ u32 addr = musb_readw(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_HIGH));
+
+ addr = addr << 16;
+
+ addr |= musb_readw(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_LOW));
+
+ return addr;
+}
+
+static inline void musb_write_hsdma_addr(void __iomem *mbase,
+ u8 bchannel, dma_addr_t dma_addr)
+{
+ musb_writew(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_LOW),
+ ((u16)((u32) dma_addr & 0xFFFF)));
+ musb_writew(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_HIGH),
+ ((u16)(((u32) dma_addr >> 16) & 0xFFFF)));
+}
+
+static inline void musb_write_hsdma_count(void __iomem *mbase,
+ u8 bchannel, u32 len)
+{
+ musb_writew(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW),
+ ((u16)((u32) len & 0xFFFF)));
+ musb_writew(mbase,
+ MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH),
+ ((u16)(((u32) len >> 16) & 0xFFFF)));
+}
+
+#endif /* CONFIG_BLACKFIN */
+
+/* control register (16-bit): */
+#define MUSB_HSDMA_ENABLE_SHIFT 0
+#define MUSB_HSDMA_TRANSMIT_SHIFT 1
+#define MUSB_HSDMA_MODE1_SHIFT 2
+#define MUSB_HSDMA_IRQENABLE_SHIFT 3
+#define MUSB_HSDMA_ENDPOINT_SHIFT 4
+#define MUSB_HSDMA_BUSERROR_SHIFT 8
+#define MUSB_HSDMA_BURSTMODE_SHIFT 9
+#define MUSB_HSDMA_BURSTMODE (3 << MUSB_HSDMA_BURSTMODE_SHIFT)
+#define MUSB_HSDMA_BURSTMODE_UNSPEC 0
+#define MUSB_HSDMA_BURSTMODE_INCR4 1
+#define MUSB_HSDMA_BURSTMODE_INCR8 2
+#define MUSB_HSDMA_BURSTMODE_INCR16 3
+
+#define MUSB_HSDMA_CHANNELS 8
+
+struct musb_dma_controller;
+
+struct musb_dma_channel {
+ struct dma_channel channel;
+ struct musb_dma_controller *controller;
+ u32 start_addr;
+ u32 len;
+ u16 max_packet_sz;
+ u8 idx;
+ u8 epnum;
+ u8 transmit;
+};
+
+struct musb_dma_controller {
+ struct dma_controller controller;
+ struct musb_dma_channel channel[MUSB_HSDMA_CHANNELS];
+ void *private_data;
+ void __iomem *base;
+ u8 channel_count;
+ u8 used_channels;
+ u8 irq;
+};
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index ce6c162920f7..901dffdf23b1 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -58,10 +58,10 @@ static void musb_do_idle(unsigned long _musb)
#endif
u8 devctl;
- devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
-
spin_lock_irqsave(&musb->lock, flags);
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
switch (musb->xceiv.state) {
case OTG_STATE_A_WAIT_BCON:
devctl &= ~MUSB_DEVCTL_SESSION;
@@ -196,7 +196,7 @@ static int omap_set_power(struct otg_transceiver *x, unsigned mA)
static int musb_platform_resume(struct musb *musb);
-void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
{
u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
@@ -204,15 +204,24 @@ void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
switch (musb_mode) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
case MUSB_HOST:
otg_set_host(&musb->xceiv, musb->xceiv.host);
break;
+#endif
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
case MUSB_PERIPHERAL:
otg_set_peripheral(&musb->xceiv, musb->xceiv.gadget);
break;
+#endif
+#ifdef CONFIG_USB_MUSB_OTG
case MUSB_OTG:
break;
+#endif
+ default:
+ return -EINVAL;
}
+ return 0;
}
int __init musb_platform_init(struct musb *musb)
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index ee8fca92a4ac..9e20fd070d71 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -598,7 +598,7 @@ static void tusb_source_power(struct musb *musb, int is_on)
* and peripheral modes in non-OTG configurations by reconfiguring hardware
* and then setting musb->board_mode. For now, only support OTG mode.
*/
-void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
{
void __iomem *tbase = musb->ctrl_base;
u32 otg_stat, phy_otg_ctrl, phy_otg_ena, dev_conf;
@@ -641,7 +641,8 @@ void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
#endif
default:
- DBG(2, "Trying to set unknown mode %i\n", musb_mode);
+ DBG(2, "Trying to set mode %i\n", musb_mode);
+ return -EINVAL;
}
musb_writel(tbase, TUSB_PHY_OTG_CTRL,
@@ -655,6 +656,8 @@ void musb_platform_set_mode(struct musb *musb, u8 musb_mode)
!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS))
INFO("Cannot be peripheral with mini-A cable "
"otg_stat: %08x\n", otg_stat);
+
+ return 0;
}
static inline unsigned long
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
new file mode 100644
index 000000000000..8e8dbdb9b39b
--- /dev/null
+++ b/drivers/usb/otg/Kconfig
@@ -0,0 +1,54 @@
+#
+# USB OTG infrastructure may be needed for peripheral-only, host-only,
+# or OTG-capable configurations when OTG transceivers or controllers
+# are used.
+#
+
+comment "OTG and related infrastructure"
+
+if USB || USB_GADGET
+
+config USB_OTG_UTILS
+ bool
+ help
+ Select this to make sure the build includes objects from
+ the OTG infrastructure directory.
+
+#
+# USB Transceiver Drivers
+#
+config USB_GPIO_VBUS
+ tristate "GPIO based peripheral-only VBUS sensing 'transceiver'"
+ depends on GENERIC_GPIO
+ select USB_OTG_UTILS
+ help
+ Provides simple GPIO VBUS sensing for controllers with an
+ internal transceiver via the otg_transceiver interface, and
+ optionally control of a D+ pullup GPIO as well as a VBUS
+ current limit regulator.
+
+config ISP1301_OMAP
+ tristate "Philips ISP1301 with OMAP OTG"
+ depends on I2C && ARCH_OMAP_OTG
+ select USB_OTG_UTILS
+ help
+ If you say yes here you get support for the Philips ISP1301
+ USB-On-The-Go transceiver working with the OMAP OTG controller.
+ The ISP1301 is a full speed USB transceiver which is used in
+ products including H2, H3, and H4 development boards for Texas
+ Instruments OMAP processors.
+
+ This driver can also be built as a module. If so, the module
+ will be called isp1301_omap.
+
+config TWL4030_USB
+ tristate "TWL4030 USB Transceiver Driver"
+ depends on TWL4030_CORE
+ select USB_OTG_UTILS
+ help
+ Enable this to support the USB OTG transceiver on TWL4030
+ family chips (including the TWL5030 and TPS659x0 devices).
+ This transceiver supports high and full speed devices plus,
+ in host mode, low speed.
+
+endif # USB || OTG
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
new file mode 100644
index 000000000000..d73c7cf5e2f7
--- /dev/null
+++ b/drivers/usb/otg/Makefile
@@ -0,0 +1,15 @@
+#
+# OTG infrastructure and transceiver drivers
+#
+
+# infrastructure
+obj-$(CONFIG_USB_OTG_UTILS) += otg.o
+
+# transceiver drivers
+obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
+obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
+obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
+
+ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG
+ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG
+
diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c
new file mode 100644
index 000000000000..63a6036f04be
--- /dev/null
+++ b/drivers/usb/otg/gpio_vbus.c
@@ -0,0 +1,335 @@
+/*
+ * gpio-vbus.c - simple GPIO VBUS sensing driver for B peripheral devices
+ *
+ * Copyright (c) 2008 Philipp Zabel <philipp.zabel@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+
+#include <linux/regulator/consumer.h>
+
+#include <linux/usb/gadget.h>
+#include <linux/usb/gpio_vbus.h>
+#include <linux/usb/otg.h>
+
+
+/*
+ * A simple GPIO VBUS sensing driver for B peripheral only devices
+ * with internal transceivers. It can control a D+ pullup GPIO and
+ * a regulator to limit the current drawn from VBUS.
+ *
+ * Needs to be loaded before the UDC driver that will use it.
+ */
+struct gpio_vbus_data {
+ struct otg_transceiver otg;
+ struct device *dev;
+ struct regulator *vbus_draw;
+ int vbus_draw_enabled;
+ unsigned mA;
+};
+
+
+/*
+ * This driver relies on "both edges" triggering. VBUS has 100 msec to
+ * stabilize, so the peripheral controller driver may need to cope with
+ * some bouncing due to current surges (e.g. charging local capacitance)
+ * and contact chatter.
+ *
+ * REVISIT in desperate straits, toggling between rising and falling
+ * edges might be workable.
+ */
+#define VBUS_IRQ_FLAGS \
+ ( IRQF_SAMPLE_RANDOM | IRQF_SHARED \
+ | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING )
+
+
+/* interface to regulator framework */
+static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
+{
+ struct regulator *vbus_draw = gpio_vbus->vbus_draw;
+ int enabled;
+
+ if (!vbus_draw)
+ return;
+
+ enabled = gpio_vbus->vbus_draw_enabled;
+ if (mA) {
+ regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
+ if (!enabled) {
+ regulator_enable(vbus_draw);
+ gpio_vbus->vbus_draw_enabled = 1;
+ }
+ } else {
+ if (enabled) {
+ regulator_disable(vbus_draw);
+ gpio_vbus->vbus_draw_enabled = 0;
+ }
+ }
+ gpio_vbus->mA = mA;
+}
+
+/* VBUS change IRQ handler */
+static irqreturn_t gpio_vbus_irq(int irq, void *data)
+{
+ struct platform_device *pdev = data;
+ struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+ struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
+ int gpio, vbus;
+
+ vbus = gpio_get_value(pdata->gpio_vbus);
+ if (pdata->gpio_vbus_inverted)
+ vbus = !vbus;
+
+ dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n",
+ vbus ? "supplied" : "inactive",
+ gpio_vbus->otg.gadget ? gpio_vbus->otg.gadget->name : "none");
+
+ if (!gpio_vbus->otg.gadget)
+ return IRQ_HANDLED;
+
+ /* Peripheral controllers which manage the pullup themselves won't have
+ * gpio_pullup configured here. If it's configured here, we'll do what
+ * isp1301_omap::b_peripheral() does and enable the pullup here... although
+ * that may complicate usb_gadget_{,dis}connect() support.
+ */
+ gpio = pdata->gpio_pullup;
+ if (vbus) {
+ gpio_vbus->otg.state = OTG_STATE_B_PERIPHERAL;
+ usb_gadget_vbus_connect(gpio_vbus->otg.gadget);
+
+ /* drawing a "unit load" is *always* OK, except for OTG */
+ set_vbus_draw(gpio_vbus, 100);
+
+ /* optionally enable D+ pullup */
+ if (gpio_is_valid(gpio))
+ gpio_set_value(gpio, !pdata->gpio_pullup_inverted);
+ } else {
+ /* optionally disable D+ pullup */
+ if (gpio_is_valid(gpio))
+ gpio_set_value(gpio, pdata->gpio_pullup_inverted);
+
+ set_vbus_draw(gpio_vbus, 0);
+
+ usb_gadget_vbus_disconnect(gpio_vbus->otg.gadget);
+ gpio_vbus->otg.state = OTG_STATE_B_IDLE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* OTG transceiver interface */
+
+/* bind/unbind the peripheral controller */
+static int gpio_vbus_set_peripheral(struct otg_transceiver *otg,
+ struct usb_gadget *gadget)
+{
+ struct gpio_vbus_data *gpio_vbus;
+ struct gpio_vbus_mach_info *pdata;
+ struct platform_device *pdev;
+ int gpio, irq;
+
+ gpio_vbus = container_of(otg, struct gpio_vbus_data, otg);
+ pdev = to_platform_device(gpio_vbus->dev);
+ pdata = gpio_vbus->dev->platform_data;
+ irq = gpio_to_irq(pdata->gpio_vbus);
+ gpio = pdata->gpio_pullup;
+
+ if (!gadget) {
+ dev_dbg(&pdev->dev, "unregistering gadget '%s'\n",
+ otg->gadget->name);
+
+ /* optionally disable D+ pullup */
+ if (gpio_is_valid(gpio))
+ gpio_set_value(gpio, pdata->gpio_pullup_inverted);
+
+ set_vbus_draw(gpio_vbus, 0);
+
+ usb_gadget_vbus_disconnect(otg->gadget);
+ otg->state = OTG_STATE_UNDEFINED;
+
+ otg->gadget = NULL;
+ return 0;
+ }
+
+ otg->gadget = gadget;
+ dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name);
+
+ /* initialize connection state */
+ gpio_vbus_irq(irq, pdev);
+ return 0;
+}
+
+/* effective for B devices, ignored for A-peripheral */
+static int gpio_vbus_set_power(struct otg_transceiver *otg, unsigned mA)
+{
+ struct gpio_vbus_data *gpio_vbus;
+
+ gpio_vbus = container_of(otg, struct gpio_vbus_data, otg);
+
+ if (otg->state == OTG_STATE_B_PERIPHERAL)
+ set_vbus_draw(gpio_vbus, mA);
+ return 0;
+}
+
+/* for non-OTG B devices: set/clear transceiver suspend mode */
+static int gpio_vbus_set_suspend(struct otg_transceiver *otg, int suspend)
+{
+ struct gpio_vbus_data *gpio_vbus;
+
+ gpio_vbus = container_of(otg, struct gpio_vbus_data, otg);
+
+ /* draw max 0 mA from vbus in suspend mode; or the previously
+ * recorded amount of current if not suspended
+ *
+ * NOTE: high powered configs (mA > 100) may draw up to 2.5 mA
+ * if they're wake-enabled ... we don't handle that yet.
+ */
+ return gpio_vbus_set_power(otg, suspend ? 0 : gpio_vbus->mA);
+}
+
+/* platform driver interface */
+
+static int __init gpio_vbus_probe(struct platform_device *pdev)
+{
+ struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+ struct gpio_vbus_data *gpio_vbus;
+ struct resource *res;
+ int err, gpio, irq;
+
+ if (!pdata || !gpio_is_valid(pdata->gpio_vbus))
+ return -EINVAL;
+ gpio = pdata->gpio_vbus;
+
+ gpio_vbus = kzalloc(sizeof(struct gpio_vbus_data), GFP_KERNEL);
+ if (!gpio_vbus)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, gpio_vbus);
+ gpio_vbus->dev = &pdev->dev;
+ gpio_vbus->otg.label = "gpio-vbus";
+ gpio_vbus->otg.state = OTG_STATE_UNDEFINED;
+ gpio_vbus->otg.set_peripheral = gpio_vbus_set_peripheral;
+ gpio_vbus->otg.set_power = gpio_vbus_set_power;
+ gpio_vbus->otg.set_suspend = gpio_vbus_set_suspend;
+
+ err = gpio_request(gpio, "vbus_detect");
+ if (err) {
+ dev_err(&pdev->dev, "can't request vbus gpio %d, err: %d\n",
+ gpio, err);
+ goto err_gpio;
+ }
+ gpio_direction_input(gpio);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res) {
+ irq = res->start;
+ res->flags &= IRQF_TRIGGER_MASK;
+ res->flags |= IRQF_SAMPLE_RANDOM | IRQF_SHARED;
+ } else
+ irq = gpio_to_irq(gpio);
+
+ /* if data line pullup is in use, initialize it to "not pulling up" */
+ gpio = pdata->gpio_pullup;
+ if (gpio_is_valid(gpio)) {
+ err = gpio_request(gpio, "udc_pullup");
+ if (err) {
+ dev_err(&pdev->dev,
+ "can't request pullup gpio %d, err: %d\n",
+ gpio, err);
+ gpio_free(pdata->gpio_vbus);
+ goto err_gpio;
+ }
+ gpio_direction_output(gpio, pdata->gpio_pullup_inverted);
+ }
+
+ err = request_irq(irq, gpio_vbus_irq, VBUS_IRQ_FLAGS,
+ "vbus_detect", pdev);
+ if (err) {
+ dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
+ irq, err);
+ goto err_irq;
+ }
+
+ /* only active when a gadget is registered */
+ err = otg_set_transceiver(&gpio_vbus->otg);
+ if (err) {
+ dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
+ err);
+ goto err_otg;
+ }
+
+ gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw");
+ if (IS_ERR(gpio_vbus->vbus_draw)) {
+ dev_dbg(&pdev->dev, "can't get vbus_draw regulator, err: %ld\n",
+ PTR_ERR(gpio_vbus->vbus_draw));
+ gpio_vbus->vbus_draw = NULL;
+ }
+
+ return 0;
+err_otg:
+ free_irq(irq, &pdev->dev);
+err_irq:
+ if (gpio_is_valid(pdata->gpio_pullup))
+ gpio_free(pdata->gpio_pullup);
+ gpio_free(pdata->gpio_vbus);
+err_gpio:
+ platform_set_drvdata(pdev, NULL);
+ kfree(gpio_vbus);
+ return err;
+}
+
+static int __exit gpio_vbus_remove(struct platform_device *pdev)
+{
+ struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
+ struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
+ int gpio = pdata->gpio_vbus;
+
+ regulator_put(gpio_vbus->vbus_draw);
+
+ otg_set_transceiver(NULL);
+
+ free_irq(gpio_to_irq(gpio), &pdev->dev);
+ if (gpio_is_valid(pdata->gpio_pullup))
+ gpio_free(pdata->gpio_pullup);
+ gpio_free(gpio);
+ platform_set_drvdata(pdev, NULL);
+ kfree(gpio_vbus);
+
+ return 0;
+}
+
+/* NOTE: the gpio-vbus device may *NOT* be hotplugged */
+
+MODULE_ALIAS("platform:gpio-vbus");
+
+static struct platform_driver gpio_vbus_driver = {
+ .driver = {
+ .name = "gpio-vbus",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(gpio_vbus_remove),
+};
+
+static int __init gpio_vbus_init(void)
+{
+ return platform_driver_probe(&gpio_vbus_driver, gpio_vbus_probe);
+}
+module_init(gpio_vbus_init);
+
+static void __exit gpio_vbus_exit(void)
+{
+ platform_driver_unregister(&gpio_vbus_driver);
+}
+module_exit(gpio_vbus_exit);
+
+MODULE_DESCRIPTION("simple GPIO controlled OTG transceiver driver");
+MODULE_AUTHOR("Philipp Zabel");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c
index e0d56ef2bcb0..e0d56ef2bcb0 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/usb/otg/isp1301_omap.c
diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
new file mode 100644
index 000000000000..ff318fae7d4d
--- /dev/null
+++ b/drivers/usb/otg/otg.c
@@ -0,0 +1,65 @@
+/*
+ * otg.c -- USB OTG utility code
+ *
+ * Copyright (C) 2004 Texas Instruments
+ *
+ * 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/kernel.h>
+#include <linux/device.h>
+
+#include <linux/usb/otg.h>
+
+static struct otg_transceiver *xceiv;
+
+/**
+ * otg_get_transceiver - find the (single) OTG transceiver
+ *
+ * Returns the transceiver driver, after getting a refcount to it; or
+ * null if there is no such transceiver. The caller is responsible for
+ * calling otg_put_transceiver() to release that count.
+ *
+ * For use by USB host and peripheral drivers.
+ */
+struct otg_transceiver *otg_get_transceiver(void)
+{
+ if (xceiv)
+ get_device(xceiv->dev);
+ return xceiv;
+}
+EXPORT_SYMBOL(otg_get_transceiver);
+
+/**
+ * otg_put_transceiver - release the (single) OTG transceiver
+ * @x: the transceiver returned by otg_get_transceiver()
+ *
+ * Releases a refcount the caller received from otg_get_transceiver().
+ *
+ * For use by USB host and peripheral drivers.
+ */
+void otg_put_transceiver(struct otg_transceiver *x)
+{
+ put_device(x->dev);
+}
+EXPORT_SYMBOL(otg_put_transceiver);
+
+/**
+ * otg_set_transceiver - declare the (single) OTG transceiver
+ * @x: the USB OTG transceiver to be used; or NULL
+ *
+ * This call is exclusively for use by transceiver drivers, which
+ * coordinate the activities of drivers for host and peripheral
+ * controllers, and in some cases for VBUS current regulation.
+ */
+int otg_set_transceiver(struct otg_transceiver *x)
+{
+ if (xceiv && x)
+ return -EBUSY;
+ xceiv = x;
+ return 0;
+}
+EXPORT_SYMBOL(otg_set_transceiver);
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
new file mode 100644
index 000000000000..416e4410be02
--- /dev/null
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -0,0 +1,721 @@
+/*
+ * twl4030_usb - TWL4030 USB transceiver, talking to OMAP OTG controller
+ *
+ * Copyright (C) 2004-2007 Texas Instruments
+ * Copyright (C) 2008 Nokia Corporation
+ * Contact: Felipe Balbi <felipe.balbi@nokia.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.
+ *
+ * Current status:
+ * - HS USB ULPI mode works.
+ * - 3-pin mode support may be added in future.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/usb/otg.h>
+#include <linux/i2c/twl4030.h>
+
+
+/* Register defines */
+
+#define VENDOR_ID_LO 0x00
+#define VENDOR_ID_HI 0x01
+#define PRODUCT_ID_LO 0x02
+#define PRODUCT_ID_HI 0x03
+
+#define FUNC_CTRL 0x04
+#define FUNC_CTRL_SET 0x05
+#define FUNC_CTRL_CLR 0x06
+#define FUNC_CTRL_SUSPENDM (1 << 6)
+#define FUNC_CTRL_RESET (1 << 5)
+#define FUNC_CTRL_OPMODE_MASK (3 << 3) /* bits 3 and 4 */
+#define FUNC_CTRL_OPMODE_NORMAL (0 << 3)
+#define FUNC_CTRL_OPMODE_NONDRIVING (1 << 3)
+#define FUNC_CTRL_OPMODE_DISABLE_BIT_NRZI (2 << 3)
+#define FUNC_CTRL_TERMSELECT (1 << 2)
+#define FUNC_CTRL_XCVRSELECT_MASK (3 << 0) /* bits 0 and 1 */
+#define FUNC_CTRL_XCVRSELECT_HS (0 << 0)
+#define FUNC_CTRL_XCVRSELECT_FS (1 << 0)
+#define FUNC_CTRL_XCVRSELECT_LS (2 << 0)
+#define FUNC_CTRL_XCVRSELECT_FS4LS (3 << 0)
+
+#define IFC_CTRL 0x07
+#define IFC_CTRL_SET 0x08
+#define IFC_CTRL_CLR 0x09
+#define IFC_CTRL_INTERFACE_PROTECT_DISABLE (1 << 7)
+#define IFC_CTRL_AUTORESUME (1 << 4)
+#define IFC_CTRL_CLOCKSUSPENDM (1 << 3)
+#define IFC_CTRL_CARKITMODE (1 << 2)
+#define IFC_CTRL_FSLSSERIALMODE_3PIN (1 << 1)
+
+#define TWL4030_OTG_CTRL 0x0A
+#define TWL4030_OTG_CTRL_SET 0x0B
+#define TWL4030_OTG_CTRL_CLR 0x0C
+#define TWL4030_OTG_CTRL_DRVVBUS (1 << 5)
+#define TWL4030_OTG_CTRL_CHRGVBUS (1 << 4)
+#define TWL4030_OTG_CTRL_DISCHRGVBUS (1 << 3)
+#define TWL4030_OTG_CTRL_DMPULLDOWN (1 << 2)
+#define TWL4030_OTG_CTRL_DPPULLDOWN (1 << 1)
+#define TWL4030_OTG_CTRL_IDPULLUP (1 << 0)
+
+#define USB_INT_EN_RISE 0x0D
+#define USB_INT_EN_RISE_SET 0x0E
+#define USB_INT_EN_RISE_CLR 0x0F
+#define USB_INT_EN_FALL 0x10
+#define USB_INT_EN_FALL_SET 0x11
+#define USB_INT_EN_FALL_CLR 0x12
+#define USB_INT_STS 0x13
+#define USB_INT_LATCH 0x14
+#define USB_INT_IDGND (1 << 4)
+#define USB_INT_SESSEND (1 << 3)
+#define USB_INT_SESSVALID (1 << 2)
+#define USB_INT_VBUSVALID (1 << 1)
+#define USB_INT_HOSTDISCONNECT (1 << 0)
+
+#define CARKIT_CTRL 0x19
+#define CARKIT_CTRL_SET 0x1A
+#define CARKIT_CTRL_CLR 0x1B
+#define CARKIT_CTRL_MICEN (1 << 6)
+#define CARKIT_CTRL_SPKRIGHTEN (1 << 5)
+#define CARKIT_CTRL_SPKLEFTEN (1 << 4)
+#define CARKIT_CTRL_RXDEN (1 << 3)
+#define CARKIT_CTRL_TXDEN (1 << 2)
+#define CARKIT_CTRL_IDGNDDRV (1 << 1)
+#define CARKIT_CTRL_CARKITPWR (1 << 0)
+#define CARKIT_PLS_CTRL 0x22
+#define CARKIT_PLS_CTRL_SET 0x23
+#define CARKIT_PLS_CTRL_CLR 0x24
+#define CARKIT_PLS_CTRL_SPKRRIGHT_BIASEN (1 << 3)
+#define CARKIT_PLS_CTRL_SPKRLEFT_BIASEN (1 << 2)
+#define CARKIT_PLS_CTRL_RXPLSEN (1 << 1)
+#define CARKIT_PLS_CTRL_TXPLSEN (1 << 0)
+
+#define MCPC_CTRL 0x30
+#define MCPC_CTRL_SET 0x31
+#define MCPC_CTRL_CLR 0x32
+#define MCPC_CTRL_RTSOL (1 << 7)
+#define MCPC_CTRL_EXTSWR (1 << 6)
+#define MCPC_CTRL_EXTSWC (1 << 5)
+#define MCPC_CTRL_VOICESW (1 << 4)
+#define MCPC_CTRL_OUT64K (1 << 3)
+#define MCPC_CTRL_RTSCTSSW (1 << 2)
+#define MCPC_CTRL_HS_UART (1 << 0)
+
+#define MCPC_IO_CTRL 0x33
+#define MCPC_IO_CTRL_SET 0x34
+#define MCPC_IO_CTRL_CLR 0x35
+#define MCPC_IO_CTRL_MICBIASEN (1 << 5)
+#define MCPC_IO_CTRL_CTS_NPU (1 << 4)
+#define MCPC_IO_CTRL_RXD_PU (1 << 3)
+#define MCPC_IO_CTRL_TXDTYP (1 << 2)
+#define MCPC_IO_CTRL_CTSTYP (1 << 1)
+#define MCPC_IO_CTRL_RTSTYP (1 << 0)
+
+#define MCPC_CTRL2 0x36
+#define MCPC_CTRL2_SET 0x37
+#define MCPC_CTRL2_CLR 0x38
+#define MCPC_CTRL2_MCPC_CK_EN (1 << 0)
+
+#define OTHER_FUNC_CTRL 0x80
+#define OTHER_FUNC_CTRL_SET 0x81
+#define OTHER_FUNC_CTRL_CLR 0x82
+#define OTHER_FUNC_CTRL_BDIS_ACON_EN (1 << 4)
+#define OTHER_FUNC_CTRL_FIVEWIRE_MODE (1 << 2)
+
+#define OTHER_IFC_CTRL 0x83
+#define OTHER_IFC_CTRL_SET 0x84
+#define OTHER_IFC_CTRL_CLR 0x85
+#define OTHER_IFC_CTRL_OE_INT_EN (1 << 6)
+#define OTHER_IFC_CTRL_CEA2011_MODE (1 << 5)
+#define OTHER_IFC_CTRL_FSLSSERIALMODE_4PIN (1 << 4)
+#define OTHER_IFC_CTRL_HIZ_ULPI_60MHZ_OUT (1 << 3)
+#define OTHER_IFC_CTRL_HIZ_ULPI (1 << 2)
+#define OTHER_IFC_CTRL_ALT_INT_REROUTE (1 << 0)
+
+#define OTHER_INT_EN_RISE 0x86
+#define OTHER_INT_EN_RISE_SET 0x87
+#define OTHER_INT_EN_RISE_CLR 0x88
+#define OTHER_INT_EN_FALL 0x89
+#define OTHER_INT_EN_FALL_SET 0x8A
+#define OTHER_INT_EN_FALL_CLR 0x8B
+#define OTHER_INT_STS 0x8C
+#define OTHER_INT_LATCH 0x8D
+#define OTHER_INT_VB_SESS_VLD (1 << 7)
+#define OTHER_INT_DM_HI (1 << 6) /* not valid for "latch" reg */
+#define OTHER_INT_DP_HI (1 << 5) /* not valid for "latch" reg */
+#define OTHER_INT_BDIS_ACON (1 << 3) /* not valid for "fall" regs */
+#define OTHER_INT_MANU (1 << 1)
+#define OTHER_INT_ABNORMAL_STRESS (1 << 0)
+
+#define ID_STATUS 0x96
+#define ID_RES_FLOAT (1 << 4)
+#define ID_RES_440K (1 << 3)
+#define ID_RES_200K (1 << 2)
+#define ID_RES_102K (1 << 1)
+#define ID_RES_GND (1 << 0)
+
+#define POWER_CTRL 0xAC
+#define POWER_CTRL_SET 0xAD
+#define POWER_CTRL_CLR 0xAE
+#define POWER_CTRL_OTG_ENAB (1 << 5)
+
+#define OTHER_IFC_CTRL2 0xAF
+#define OTHER_IFC_CTRL2_SET 0xB0
+#define OTHER_IFC_CTRL2_CLR 0xB1
+#define OTHER_IFC_CTRL2_ULPI_STP_LOW (1 << 4)
+#define OTHER_IFC_CTRL2_ULPI_TXEN_POL (1 << 3)
+#define OTHER_IFC_CTRL2_ULPI_4PIN_2430 (1 << 2)
+#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_MASK (3 << 0) /* bits 0 and 1 */
+#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT1N (0 << 0)
+#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT2N (1 << 0)
+
+#define REG_CTRL_EN 0xB2
+#define REG_CTRL_EN_SET 0xB3
+#define REG_CTRL_EN_CLR 0xB4
+#define REG_CTRL_ERROR 0xB5
+#define ULPI_I2C_CONFLICT_INTEN (1 << 0)
+
+#define OTHER_FUNC_CTRL2 0xB8
+#define OTHER_FUNC_CTRL2_SET 0xB9
+#define OTHER_FUNC_CTRL2_CLR 0xBA
+#define OTHER_FUNC_CTRL2_VBAT_TIMER_EN (1 << 0)
+
+/* following registers do not have separate _clr and _set registers */
+#define VBUS_DEBOUNCE 0xC0
+#define ID_DEBOUNCE 0xC1
+#define VBAT_TIMER 0xD3
+#define PHY_PWR_CTRL 0xFD
+#define PHY_PWR_PHYPWD (1 << 0)
+#define PHY_CLK_CTRL 0xFE
+#define PHY_CLK_CTRL_CLOCKGATING_EN (1 << 2)
+#define PHY_CLK_CTRL_CLK32K_EN (1 << 1)
+#define REQ_PHY_DPLL_CLK (1 << 0)
+#define PHY_CLK_CTRL_STS 0xFF
+#define PHY_DPLL_CLK (1 << 0)
+
+/* In module TWL4030_MODULE_PM_MASTER */
+#define PROTECT_KEY 0x0E
+
+/* In module TWL4030_MODULE_PM_RECEIVER */
+#define VUSB_DEDICATED1 0x7D
+#define VUSB_DEDICATED2 0x7E
+#define VUSB1V5_DEV_GRP 0x71
+#define VUSB1V5_TYPE 0x72
+#define VUSB1V5_REMAP 0x73
+#define VUSB1V8_DEV_GRP 0x74
+#define VUSB1V8_TYPE 0x75
+#define VUSB1V8_REMAP 0x76
+#define VUSB3V1_DEV_GRP 0x77
+#define VUSB3V1_TYPE 0x78
+#define VUSB3V1_REMAP 0x79
+
+/* In module TWL4030_MODULE_INTBR */
+#define PMBR1 0x0D
+#define GPIO_USB_4PIN_ULPI_2430C (3 << 0)
+
+
+
+enum linkstat {
+ USB_LINK_UNKNOWN = 0,
+ USB_LINK_NONE,
+ USB_LINK_VBUS,
+ USB_LINK_ID,
+};
+
+struct twl4030_usb {
+ struct otg_transceiver otg;
+ struct device *dev;
+
+ /* for vbus reporting with irqs disabled */
+ spinlock_t lock;
+
+ /* pin configuration */
+ enum twl4030_usb_mode usb_mode;
+
+ int irq;
+ u8 linkstat;
+ u8 asleep;
+ bool irq_enabled;
+};
+
+/* internal define on top of container_of */
+#define xceiv_to_twl(x) container_of((x), struct twl4030_usb, otg);
+
+/*-------------------------------------------------------------------------*/
+
+static int twl4030_i2c_write_u8_verify(struct twl4030_usb *twl,
+ u8 module, u8 data, u8 address)
+{
+ u8 check;
+
+ if ((twl4030_i2c_write_u8(module, data, address) >= 0) &&
+ (twl4030_i2c_read_u8(module, &check, address) >= 0) &&
+ (check == data))
+ return 0;
+ dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n",
+ 1, module, address, check, data);
+
+ /* Failed once: Try again */
+ if ((twl4030_i2c_write_u8(module, data, address) >= 0) &&
+ (twl4030_i2c_read_u8(module, &check, address) >= 0) &&
+ (check == data))
+ return 0;
+ dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n",
+ 2, module, address, check, data);
+
+ /* Failed again: Return error */
+ return -EBUSY;
+}
+
+#define twl4030_usb_write_verify(twl, address, data) \
+ twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_USB, (data), (address))
+
+static inline int twl4030_usb_write(struct twl4030_usb *twl,
+ u8 address, u8 data)
+{
+ int ret = 0;
+
+ ret = twl4030_i2c_write_u8(TWL4030_MODULE_USB, data, address);
+ if (ret < 0)
+ dev_dbg(twl->dev,
+ "TWL4030:USB:Write[0x%x] Error %d\n", address, ret);
+ return ret;
+}
+
+static inline int twl4030_readb(struct twl4030_usb *twl, u8 module, u8 address)
+{
+ u8 data;
+ int ret = 0;
+
+ ret = twl4030_i2c_read_u8(module, &data, address);
+ if (ret >= 0)
+ ret = data;
+ else
+ dev_dbg(twl->dev,
+ "TWL4030:readb[0x%x,0x%x] Error %d\n",
+ module, address, ret);
+
+ return ret;
+}
+
+static inline int twl4030_usb_read(struct twl4030_usb *twl, u8 address)
+{
+ return twl4030_readb(twl, TWL4030_MODULE_USB, address);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline int
+twl4030_usb_set_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
+{
+ return twl4030_usb_write(twl, reg + 1, bits);
+}
+
+static inline int
+twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
+{
+ return twl4030_usb_write(twl, reg + 2, bits);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl)
+{
+ int status;
+ int linkstat = USB_LINK_UNKNOWN;
+
+ /* STS_HW_CONDITIONS */
+ status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER, 0x0f);
+ if (status < 0)
+ dev_err(twl->dev, "USB link status err %d\n", status);
+ else if (status & BIT(7))
+ linkstat = USB_LINK_VBUS;
+ else if (status & BIT(2))
+ linkstat = USB_LINK_ID;
+ else
+ linkstat = USB_LINK_NONE;
+
+ dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
+ status, status, linkstat);
+
+ /* REVISIT this assumes host and peripheral controllers
+ * are registered, and that both are active...
+ */
+
+ spin_lock_irq(&twl->lock);
+ twl->linkstat = linkstat;
+ if (linkstat == USB_LINK_ID) {
+ twl->otg.default_a = true;
+ twl->otg.state = OTG_STATE_A_IDLE;
+ } else {
+ twl->otg.default_a = false;
+ twl->otg.state = OTG_STATE_B_IDLE;
+ }
+ spin_unlock_irq(&twl->lock);
+
+ return linkstat;
+}
+
+static void twl4030_usb_set_mode(struct twl4030_usb *twl, int mode)
+{
+ twl->usb_mode = mode;
+
+ switch (mode) {
+ case T2_USB_MODE_ULPI:
+ twl4030_usb_clear_bits(twl, IFC_CTRL, IFC_CTRL_CARKITMODE);
+ twl4030_usb_set_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
+ twl4030_usb_clear_bits(twl, FUNC_CTRL,
+ FUNC_CTRL_XCVRSELECT_MASK |
+ FUNC_CTRL_OPMODE_MASK);
+ break;
+ case -1:
+ /* FIXME: power on defaults */
+ break;
+ default:
+ dev_err(twl->dev, "unsupported T2 transceiver mode %d\n",
+ mode);
+ break;
+ };
+}
+
+static void twl4030_i2c_access(struct twl4030_usb *twl, int on)
+{
+ unsigned long timeout;
+ int val = twl4030_usb_read(twl, PHY_CLK_CTRL);
+
+ if (val >= 0) {
+ if (on) {
+ /* enable DPLL to access PHY registers over I2C */
+ val |= REQ_PHY_DPLL_CLK;
+ WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL,
+ (u8)val) < 0);
+
+ timeout = jiffies + HZ;
+ while (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) &
+ PHY_DPLL_CLK)
+ && time_before(jiffies, timeout))
+ udelay(10);
+ if (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) &
+ PHY_DPLL_CLK))
+ dev_err(twl->dev, "Timeout setting T2 HSUSB "
+ "PHY DPLL clock\n");
+ } else {
+ /* let ULPI control the DPLL clock */
+ val &= ~REQ_PHY_DPLL_CLK;
+ WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL,
+ (u8)val) < 0);
+ }
+ }
+}
+
+static void twl4030_phy_power(struct twl4030_usb *twl, int on)
+{
+ u8 pwr;
+
+ pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
+ if (on) {
+ pwr &= ~PHY_PWR_PHYPWD;
+ WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
+ twl4030_usb_write(twl, PHY_CLK_CTRL,
+ twl4030_usb_read(twl, PHY_CLK_CTRL) |
+ (PHY_CLK_CTRL_CLOCKGATING_EN |
+ PHY_CLK_CTRL_CLK32K_EN));
+ } else {
+ pwr |= PHY_PWR_PHYPWD;
+ WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
+ }
+}
+
+static void twl4030_phy_suspend(struct twl4030_usb *twl, int controller_off)
+{
+ if (twl->asleep)
+ return;
+
+ twl4030_phy_power(twl, 0);
+ twl->asleep = 1;
+}
+
+static void twl4030_phy_resume(struct twl4030_usb *twl)
+{
+ if (!twl->asleep)
+ return;
+
+ twl4030_phy_power(twl, 1);
+ twl4030_i2c_access(twl, 1);
+ twl4030_usb_set_mode(twl, twl->usb_mode);
+ if (twl->usb_mode == T2_USB_MODE_ULPI)
+ twl4030_i2c_access(twl, 0);
+ twl->asleep = 0;
+}
+
+static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
+{
+ /* Enable writing to power configuration registers */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY);
+
+ /* put VUSB3V1 LDO in active state */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);
+
+ /* input to VUSB3V1 LDO is from VBAT, not VBUS */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1);
+
+ /* turn on 3.1V regulator */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB3V1_DEV_GRP);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE);
+
+ /* turn on 1.5V regulator */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V5_DEV_GRP);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
+
+ /* turn on 1.8V regulator */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V8_DEV_GRP);
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
+
+ /* disable access to power configuration registers */
+ twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY);
+}
+
+static ssize_t twl4030_usb_vbus_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct twl4030_usb *twl = dev_get_drvdata(dev);
+ unsigned long flags;
+ int ret = -EINVAL;
+
+ spin_lock_irqsave(&twl->lock, flags);
+ ret = sprintf(buf, "%s\n",
+ (twl->linkstat == USB_LINK_VBUS) ? "on" : "off");
+ spin_unlock_irqrestore(&twl->lock, flags);
+
+ return ret;
+}
+static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL);
+
+static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
+{
+ struct twl4030_usb *twl = _twl;
+ int status;
+
+#ifdef CONFIG_LOCKDEP
+ /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+ * we don't want and can't tolerate. Although it might be
+ * friendlier not to borrow this thread context...
+ */
+ local_irq_enable();
+#endif
+
+ status = twl4030_usb_linkstat(twl);
+ if (status != USB_LINK_UNKNOWN) {
+
+ /* FIXME add a set_power() method so that B-devices can
+ * configure the charger appropriately. It's not always
+ * correct to consume VBUS power, and how much current to
+ * consume is a function of the USB configuration chosen
+ * by the host.
+ *
+ * REVISIT usb_gadget_vbus_connect(...) as needed, ditto
+ * its disconnect() sibling, when changing to/from the
+ * USB_LINK_VBUS state. musb_hdrc won't care until it
+ * starts to handle softconnect right.
+ */
+ twl4030charger_usb_en(status == USB_LINK_VBUS);
+
+ if (status == USB_LINK_NONE)
+ twl4030_phy_suspend(twl, 0);
+ else
+ twl4030_phy_resume(twl);
+ }
+ sysfs_notify(&twl->dev->kobj, NULL, "vbus");
+
+ return IRQ_HANDLED;
+}
+
+static int twl4030_set_suspend(struct otg_transceiver *x, int suspend)
+{
+ struct twl4030_usb *twl = xceiv_to_twl(x);
+
+ if (suspend)
+ twl4030_phy_suspend(twl, 1);
+ else
+ twl4030_phy_resume(twl);
+
+ return 0;
+}
+
+static int twl4030_set_peripheral(struct otg_transceiver *x,
+ struct usb_gadget *gadget)
+{
+ struct twl4030_usb *twl;
+
+ if (!x)
+ return -ENODEV;
+
+ twl = xceiv_to_twl(x);
+ twl->otg.gadget = gadget;
+ if (!gadget)
+ twl->otg.state = OTG_STATE_UNDEFINED;
+
+ return 0;
+}
+
+static int twl4030_set_host(struct otg_transceiver *x, struct usb_bus *host)
+{
+ struct twl4030_usb *twl;
+
+ if (!x)
+ return -ENODEV;
+
+ twl = xceiv_to_twl(x);
+ twl->otg.host = host;
+ if (!host)
+ twl->otg.state = OTG_STATE_UNDEFINED;
+
+ return 0;
+}
+
+static int __init twl4030_usb_probe(struct platform_device *pdev)
+{
+ struct twl4030_usb_data *pdata = pdev->dev.platform_data;
+ struct twl4030_usb *twl;
+ int status;
+
+ if (!pdata) {
+ dev_dbg(&pdev->dev, "platform_data not available\n");
+ return -EINVAL;
+ }
+
+ twl = kzalloc(sizeof *twl, GFP_KERNEL);
+ if (!twl)
+ return -ENOMEM;
+
+ twl->dev = &pdev->dev;
+ twl->irq = platform_get_irq(pdev, 0);
+ twl->otg.dev = twl->dev;
+ twl->otg.label = "twl4030";
+ twl->otg.set_host = twl4030_set_host;
+ twl->otg.set_peripheral = twl4030_set_peripheral;
+ twl->otg.set_suspend = twl4030_set_suspend;
+ twl->usb_mode = pdata->usb_mode;
+ twl->asleep = 1;
+
+ /* init spinlock for workqueue */
+ spin_lock_init(&twl->lock);
+
+ twl4030_usb_ldo_init(twl);
+ otg_set_transceiver(&twl->otg);
+
+ platform_set_drvdata(pdev, twl);
+ if (device_create_file(&pdev->dev, &dev_attr_vbus))
+ dev_warn(&pdev->dev, "could not create sysfs file\n");
+
+ /* Our job is to use irqs and status from the power module
+ * to keep the transceiver disabled when nothing's connected.
+ *
+ * FIXME we actually shouldn't start enabling it until the
+ * USB controller drivers have said they're ready, by calling
+ * set_host() and/or set_peripheral() ... OTG_capable boards
+ * need both handles, otherwise just one suffices.
+ */
+ twl->irq_enabled = true;
+ status = request_irq(twl->irq, twl4030_usb_irq,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "twl4030_usb", twl);
+ if (status < 0) {
+ dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
+ twl->irq, status);
+ kfree(twl);
+ return status;
+ }
+
+ /* The IRQ handler just handles changes from the previous states
+ * of the ID and VBUS pins ... in probe() we must initialize that
+ * previous state. The easy way: fake an IRQ.
+ *
+ * REVISIT: a real IRQ might have happened already, if PREEMPT is
+ * enabled. Else the IRQ may not yet be configured or enabled,
+ * because of scheduling delays.
+ */
+ twl4030_usb_irq(twl->irq, twl);
+
+ dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
+ return 0;
+}
+
+static int __exit twl4030_usb_remove(struct platform_device *pdev)
+{
+ struct twl4030_usb *twl = platform_get_drvdata(pdev);
+ int val;
+
+ free_irq(twl->irq, twl);
+ device_remove_file(twl->dev, &dev_attr_vbus);
+
+ /* set transceiver mode to power on defaults */
+ twl4030_usb_set_mode(twl, -1);
+
+ /* autogate 60MHz ULPI clock,
+ * clear dpll clock request for i2c access,
+ * disable 32KHz
+ */
+ val = twl4030_usb_read(twl, PHY_CLK_CTRL);
+ if (val >= 0) {
+ val |= PHY_CLK_CTRL_CLOCKGATING_EN;
+ val &= ~(PHY_CLK_CTRL_CLK32K_EN | REQ_PHY_DPLL_CLK);
+ twl4030_usb_write(twl, PHY_CLK_CTRL, (u8)val);
+ }
+
+ /* disable complete OTG block */
+ twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
+
+ twl4030_phy_power(twl, 0);
+
+ kfree(twl);
+
+ return 0;
+}
+
+static struct platform_driver twl4030_usb_driver = {
+ .probe = twl4030_usb_probe,
+ .remove = __exit_p(twl4030_usb_remove),
+ .driver = {
+ .name = "twl4030_usb",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init twl4030_usb_init(void)
+{
+ return platform_driver_register(&twl4030_usb_driver);
+}
+subsys_initcall(twl4030_usb_init);
+
+static void __exit twl4030_usb_exit(void)
+{
+ platform_driver_unregister(&twl4030_usb_driver);
+}
+module_exit(twl4030_usb_exit);
+
+MODULE_ALIAS("platform:twl4030_usb");
+MODULE_AUTHOR("Texas Instruments, Inc, Nokia Corporation");
+MODULE_DESCRIPTION("TWL4030 USB transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 70338f4ec918..b361f05cafac 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -496,6 +496,14 @@ config USB_SERIAL_SAFE_PADDED
bool "USB Secure Encapsulated Driver - Padded"
depends on USB_SERIAL_SAFE
+config USB_SERIAL_SIEMENS_MPI
+ tristate "USB Siemens MPI driver"
+ help
+ Say M here if you want to use a Siemens USB/MPI adapter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called siemens_mpi.
+
config USB_SERIAL_SIERRAWIRELESS
tristate "USB Sierra Wireless Driver"
help
@@ -565,6 +573,15 @@ config USB_SERIAL_OMNINET
To compile this driver as a module, choose M here: the
module will be called omninet.
+config USB_SERIAL_OPTICON
+ tristate "USB Opticon Barcode driver (serial mode)"
+ help
+ Say Y here if you want to use a Opticon USB Barcode device
+ in serial emulation mode.
+
+ To compile this driver as a module, choose M here: the
+ module will be called opticon.
+
config USB_SERIAL_DEBUG
tristate "USB Debugging Device"
help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 6047f818adfe..b75be91eb8f1 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -41,10 +41,12 @@ obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
obj-$(CONFIG_USB_SERIAL_MOTOROLA) += moto_modem.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
+obj-$(CONFIG_USB_SERIAL_OPTICON) += opticon.o
obj-$(CONFIG_USB_SERIAL_OPTION) += option.o
obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o
obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
+obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o
obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o
obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o
obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 69f84f0ea6fe..38ba4ea8b6bf 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -635,8 +635,7 @@ static int digi_write_oob_command(struct usb_serial_port *port,
spin_lock_irqsave(&oob_priv->dp_port_lock, flags);
while (count > 0) {
- while (oob_port->write_urb->status == -EINPROGRESS
- || oob_priv->dp_write_urb_in_use) {
+ while (oob_priv->dp_write_urb_in_use) {
cond_wait_interruptible_timeout_irqrestore(
&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
&oob_priv->dp_port_lock, flags);
@@ -699,9 +698,8 @@ static int digi_write_inb_command(struct usb_serial_port *port,
spin_lock_irqsave(&priv->dp_port_lock, flags);
while (count > 0 && ret == 0) {
- while ((port->write_urb->status == -EINPROGRESS
- || priv->dp_write_urb_in_use)
- && time_before(jiffies, timeout)) {
+ while (priv->dp_write_urb_in_use &&
+ time_before(jiffies, timeout)) {
cond_wait_interruptible_timeout_irqrestore(
&port->write_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags);
@@ -779,8 +777,7 @@ static int digi_set_modem_signals(struct usb_serial_port *port,
spin_lock_irqsave(&oob_priv->dp_port_lock, flags);
spin_lock(&port_priv->dp_port_lock);
- while (oob_port->write_urb->status == -EINPROGRESS ||
- oob_priv->dp_write_urb_in_use) {
+ while (oob_priv->dp_write_urb_in_use) {
spin_unlock(&port_priv->dp_port_lock);
cond_wait_interruptible_timeout_irqrestore(
&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
@@ -1168,12 +1165,10 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
/* be sure only one write proceeds at a time */
/* there are races on the port private buffer */
- /* and races to check write_urb->status */
spin_lock_irqsave(&priv->dp_port_lock, flags);
/* wait for urb status clear to submit another urb */
- if (port->write_urb->status == -EINPROGRESS ||
- priv->dp_write_urb_in_use) {
+ if (priv->dp_write_urb_in_use) {
/* buffer data if count is 1 (probably put_char) if possible */
if (count == 1 && priv->dp_out_buf_len < DIGI_OUT_BUF_SIZE) {
priv->dp_out_buf[priv->dp_out_buf_len++] = *buf;
@@ -1236,7 +1231,7 @@ static void digi_write_bulk_callback(struct urb *urb)
int ret = 0;
int status = urb->status;
- dbg("digi_write_bulk_callback: TOP, urb->status=%d", status);
+ dbg("digi_write_bulk_callback: TOP, status=%d", status);
/* port and serial sanity check */
if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
@@ -1266,8 +1261,7 @@ static void digi_write_bulk_callback(struct urb *urb)
/* try to send any buffered data on this port, if it is open */
spin_lock(&priv->dp_port_lock);
priv->dp_write_urb_in_use = 0;
- if (port->port.count && port->write_urb->status != -EINPROGRESS
- && priv->dp_out_buf_len > 0) {
+ if (port->port.count && priv->dp_out_buf_len > 0) {
*((unsigned char *)(port->write_urb->transfer_buffer))
= (unsigned char)DIGI_CMD_SEND_DATA;
*((unsigned char *)(port->write_urb->transfer_buffer) + 1)
@@ -1305,8 +1299,7 @@ static int digi_write_room(struct tty_struct *tty)
spin_lock_irqsave(&priv->dp_port_lock, flags);
- if (port->write_urb->status == -EINPROGRESS ||
- priv->dp_write_urb_in_use)
+ if (priv->dp_write_urb_in_use)
room = 0;
else
room = port->bulk_out_size - 2 - priv->dp_out_buf_len;
@@ -1322,8 +1315,7 @@ static int digi_chars_in_buffer(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct digi_port *priv = usb_get_serial_port_data(port);
- if (port->write_urb->status == -EINPROGRESS
- || priv->dp_write_urb_in_use) {
+ if (priv->dp_write_urb_in_use) {
dbg("digi_chars_in_buffer: port=%d, chars=%d",
priv->dp_port_num, port->bulk_out_size - 2);
/* return(port->bulk_out_size - 2); */
@@ -1702,7 +1694,7 @@ static int digi_read_inb_callback(struct urb *urb)
/* short/multiple packet check */
if (urb->actual_length != len + 2) {
dev_err(&port->dev, "%s: INCOMPLETE OR MULTIPLE PACKET, "
- "urb->status=%d, port=%d, opcode=%d, len=%d, "
+ "status=%d, port=%d, opcode=%d, len=%d, "
"actual_length=%d, status=%d\n", __func__, status,
priv->dp_port_num, opcode, len, urb->actual_length,
port_status);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index ef6cfa5a447f..c70a8f667d85 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -2030,7 +2030,7 @@ static void ftdi_process_read(struct work_struct *work)
spin_unlock_irqrestore(&priv->rx_lock, flags);
dbg("%s - deferring remainder until unthrottled",
__func__);
- return;
+ goto out;
}
spin_unlock_irqrestore(&priv->rx_lock, flags);
/* if the port is closed stop trying to read */
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 8e6a66e38db2..a26a0e2cdb4a 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1056,7 +1056,7 @@ static void garmin_write_bulk_callback(struct urb *urb)
if (status) {
dbg("%s - nonzero write bulk status received: %d",
- __func__, urb->status);
+ __func__, status);
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= CLEAR_HALT_REQUIRED;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 3ac59a8a980f..f530032ed93d 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -473,7 +473,7 @@ static struct usb_serial_driver ipw_device = {
-static int usb_ipw_init(void)
+static int __init usb_ipw_init(void)
{
int retval;
@@ -490,7 +490,7 @@ static int usb_ipw_init(void)
return 0;
}
-static void usb_ipw_exit(void)
+static void __exit usb_ipw_exit(void)
{
usb_deregister(&usb_ipw_driver);
usb_serial_deregister(&ipw_device);
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index e320972cb227..2314c6ae4fc2 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -190,10 +190,12 @@ static void iuu_rxcmd(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
int result;
+ int status = urb->status;
+
dbg("%s - enter", __func__);
- if (urb->status) {
- dbg("%s - urb->status = %d", __func__, urb->status);
+ if (status) {
+ dbg("%s - status = %d", __func__, status);
/* error stop all */
return;
}
@@ -245,10 +247,12 @@ static void iuu_update_status_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
struct iuu_private *priv = usb_get_serial_port_data(port);
u8 *st;
+ int status = urb->status;
+
dbg("%s - enter", __func__);
- if (urb->status) {
- dbg("%s - urb->status = %d", __func__, urb->status);
+ if (status) {
+ dbg("%s - status = %d", __func__, status);
/* error stop all */
return;
}
@@ -274,9 +278,9 @@ static void iuu_status_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
int result;
- dbg("%s - enter", __func__);
+ int status = urb->status;
- dbg("%s - urb->status = %d", __func__, urb->status);
+ dbg("%s - status = %d", __func__, status);
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
usb_rcvbulkpipe(port->serial->dev,
port->bulk_in_endpointAddress),
@@ -618,11 +622,12 @@ static void read_buf_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
struct tty_struct *tty;
- dbg("%s - urb->status = %d", __func__, urb->status);
+ int status = urb->status;
- if (urb->status) {
- dbg("%s - urb->status = %d", __func__, urb->status);
- if (urb->status == -EPROTO) {
+ dbg("%s - status = %d", __func__, status);
+
+ if (status) {
+ if (status == -EPROTO) {
/* reschedule needed */
}
return;
@@ -695,7 +700,7 @@ static void iuu_uart_read_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
struct iuu_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- int status;
+ int status = urb->status;
int error = 0;
int len = 0;
unsigned char *data = urb->transfer_buffer;
@@ -703,8 +708,8 @@ static void iuu_uart_read_callback(struct urb *urb)
dbg("%s - enter", __func__);
- if (urb->status) {
- dbg("%s - urb->status = %d", __func__, urb->status);
+ if (status) {
+ dbg("%s - status = %d", __func__, status);
/* error stop all */
return;
}
@@ -782,12 +787,11 @@ static void read_rxcmd_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
int result;
- dbg("%s - enter", __func__);
+ int status = urb->status;
- dbg("%s - urb->status = %d", __func__, urb->status);
+ dbg("%s - status = %d", __func__, status);
- if (urb->status) {
- dbg("%s - urb->status = %d", __func__, urb->status);
+ if (status) {
/* error stop all */
return;
}
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 96a8c7713212..2c20e88a91b3 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -214,6 +214,7 @@ struct moschip_port {
spinlock_t pool_lock;
struct urb *write_urb_pool[NUM_URBS];
char busy[NUM_URBS];
+ bool read_urb_busy;
};
@@ -679,26 +680,30 @@ static void mos7840_bulk_in_callback(struct urb *urb)
struct tty_struct *tty;
int status = urb->status;
- if (status) {
- dbg("nonzero read bulk status received: %d", status);
- return;
- }
-
mos7840_port = urb->context;
if (!mos7840_port) {
dbg("%s", "NULL mos7840_port pointer \n");
+ mos7840_port->read_urb_busy = false;
+ return;
+ }
+
+ if (status) {
+ dbg("nonzero read bulk status received: %d", status);
+ mos7840_port->read_urb_busy = false;
return;
}
port = (struct usb_serial_port *)mos7840_port->port;
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Port Paranoia failed \n");
+ mos7840_port->read_urb_busy = false;
return;
}
serial = mos7840_get_usb_serial(port, __func__);
if (!serial) {
dbg("%s\n", "Bad serial pointer ");
+ mos7840_port->read_urb_busy = false;
return;
}
@@ -725,17 +730,19 @@ static void mos7840_bulk_in_callback(struct urb *urb)
if (!mos7840_port->read_urb) {
dbg("%s", "URB KILLED !!!\n");
+ mos7840_port->read_urb_busy = false;
return;
}
mos7840_port->read_urb->dev = serial->dev;
+ mos7840_port->read_urb_busy = true;
retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
if (retval) {
- dbg(" usb_submit_urb(read bulk) failed, retval = %d",
- retval);
+ dbg("usb_submit_urb(read bulk) failed, retval = %d", retval);
+ mos7840_port->read_urb_busy = false;
}
}
@@ -1055,10 +1062,12 @@ static int mos7840_open(struct tty_struct *tty,
dbg("mos7840_open: bulkin endpoint is %d\n",
port->bulk_in_endpointAddress);
+ mos7840_port->read_urb_busy = true;
response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
if (response) {
dev_err(&port->dev, "%s - Error %d submitting control urb\n",
__func__, response);
+ mos7840_port->read_urb_busy = false;
}
/* initialize our wait queues */
@@ -1227,6 +1236,7 @@ static void mos7840_close(struct tty_struct *tty,
if (mos7840_port->read_urb) {
dbg("%s", "Shutdown bulk read\n");
usb_kill_urb(mos7840_port->read_urb);
+ mos7840_port->read_urb_busy = false;
}
if ((&mos7840_port->control_urb)) {
dbg("%s", "Shutdown control read\n");
@@ -2043,14 +2053,14 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
Data = 0x0c;
mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
- if (mos7840_port->read_urb->status != -EINPROGRESS) {
+ if (mos7840_port->read_urb_busy == false) {
mos7840_port->read_urb->dev = serial->dev;
-
+ mos7840_port->read_urb_busy = true;
status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
-
if (status) {
- dbg(" usb_submit_urb(read bulk) failed, status = %d",
+ dbg("usb_submit_urb(read bulk) failed, status = %d",
status);
+ mos7840_port->read_urb_busy = false;
}
}
wake_up(&mos7840_port->delta_msr_wait);
@@ -2117,12 +2127,14 @@ static void mos7840_set_termios(struct tty_struct *tty,
return;
}
- if (mos7840_port->read_urb->status != -EINPROGRESS) {
+ if (mos7840_port->read_urb_busy == false) {
mos7840_port->read_urb->dev = serial->dev;
+ mos7840_port->read_urb_busy = true;
status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
if (status) {
- dbg(" usb_submit_urb(read bulk) failed, status = %d",
+ dbg("usb_submit_urb(read bulk) failed, status = %d",
status);
+ mos7840_port->read_urb_busy = false;
}
}
return;
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
new file mode 100644
index 000000000000..cea326f1f105
--- /dev/null
+++ b/drivers/usb/serial/opticon.c
@@ -0,0 +1,358 @@
+/*
+ * Opticon USB barcode to serial driver
+ *
+ * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (C) 2008 Novell Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/uaccess.h>
+
+static int debug;
+
+static struct usb_device_id id_table[] = {
+ { USB_DEVICE(0x065a, 0x0009) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+/* This structure holds all of the individual device information */
+struct opticon_private {
+ struct usb_device *udev;
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ unsigned char *bulk_in_buffer;
+ struct urb *bulk_read_urb;
+ int buffer_size;
+ u8 bulk_address;
+ spinlock_t lock; /* protects the following flags */
+ bool throttled;
+ bool actually_throttled;
+ bool rts;
+};
+
+static void opticon_bulk_callback(struct urb *urb)
+{
+ struct opticon_private *priv = urb->context;
+ unsigned char *data = urb->transfer_buffer;
+ struct usb_serial_port *port = priv->port;
+ int status = urb->status;
+ struct tty_struct *tty;
+ int result;
+ int available_room = 0;
+ int data_length;
+
+ dbg("%s - port %d", __func__, port->number);
+
+ switch (status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d",
+ __func__, status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d",
+ __func__, status);
+ goto exit;
+ }
+
+ usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length,
+ data);
+
+ if (urb->actual_length > 2) {
+ data_length = urb->actual_length - 2;
+
+ /*
+ * Data from the device comes with a 2 byte header:
+ *
+ * <0x00><0x00>data...
+ * This is real data to be sent to the tty layer
+ * <0x00><0x01)level
+ * This is a RTS level change, the third byte is the RTS
+ * value (0 for low, 1 for high).
+ */
+ if ((data[0] == 0x00) && (data[1] == 0x00)) {
+ /* real data, send it to the tty layer */
+ tty = tty_port_tty_get(&port->port);
+ if (tty) {
+ available_room = tty_buffer_request_room(tty,
+ data_length);
+ if (available_room) {
+ tty_insert_flip_string(tty, data,
+ available_room);
+ tty_flip_buffer_push(tty);
+ }
+ tty_kref_put(tty);
+ }
+ } else {
+ if ((data[0] == 0x00) && (data[1] == 0x01)) {
+ if (data[2] == 0x00)
+ priv->rts = false;
+ else
+ priv->rts = true;
+ /* FIXME change the RTS level */
+ } else {
+ dev_dbg(&priv->udev->dev,
+ "Unknown data packet received from the device:"
+ " %2x %2x\n",
+ data[0], data[1]);
+ }
+ }
+ } else {
+ dev_dbg(&priv->udev->dev,
+ "Improper ammount of data received from the device, "
+ "%d bytes", urb->actual_length);
+ }
+
+exit:
+ spin_lock(&priv->lock);
+
+ /* Continue trying to always read if we should */
+ if (!priv->throttled) {
+ usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev,
+ usb_rcvbulkpipe(priv->udev,
+ priv->bulk_address),
+ priv->bulk_in_buffer, priv->buffer_size,
+ opticon_bulk_callback, priv);
+ result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __func__, result);
+ } else
+ priv->actually_throttled = true;
+ spin_unlock(&priv->lock);
+}
+
+static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port,
+ struct file *filp)
+{
+ struct opticon_private *priv = usb_get_serial_data(port->serial);
+ unsigned long flags;
+ int result = 0;
+
+ dbg("%s - port %d", __func__, port->number);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->throttled = false;
+ priv->actually_throttled = false;
+ priv->port = port;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /*
+ * Force low_latency on so that our tty_push actually forces the data
+ * through, otherwise it is scheduled, and with high data rates (like
+ * with OHCI) data can get lost.
+ */
+ if (tty)
+ tty->low_latency = 1;
+
+ /* Start reading from the device */
+ usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev,
+ usb_rcvbulkpipe(priv->udev,
+ priv->bulk_address),
+ priv->bulk_in_buffer, priv->buffer_size,
+ opticon_bulk_callback, priv);
+ result = usb_submit_urb(priv->bulk_read_urb, GFP_KERNEL);
+ if (result)
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __func__, result);
+ return result;
+}
+
+static void opticon_close(struct tty_struct *tty, struct usb_serial_port *port,
+ struct file *filp)
+{
+ struct opticon_private *priv = usb_get_serial_data(port->serial);
+
+ dbg("%s - port %d", __func__, port->number);
+
+ /* shutdown our urbs */
+ usb_kill_urb(priv->bulk_read_urb);
+}
+
+static void opticon_throttle(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct opticon_private *priv = usb_get_serial_data(port->serial);
+ unsigned long flags;
+
+ dbg("%s - port %d", __func__, port->number);
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->throttled = true;
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+static void opticon_unthrottle(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct opticon_private *priv = usb_get_serial_data(port->serial);
+ unsigned long flags;
+ int result;
+
+ dbg("%s - port %d", __func__, port->number);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->throttled = false;
+ priv->actually_throttled = false;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ priv->bulk_read_urb->dev = port->serial->dev;
+ result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&port->dev,
+ "%s - failed submitting read urb, error %d\n",
+ __func__, result);
+}
+
+static int opticon_startup(struct usb_serial *serial)
+{
+ struct opticon_private *priv;
+ struct usb_host_interface *intf;
+ int i;
+ int retval = -ENOMEM;
+ bool bulk_in_found = false;
+
+ /* create our private serial structure */
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (priv == NULL) {
+ dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
+ return -ENOMEM;
+ }
+ spin_lock_init(&priv->lock);
+ priv->serial = serial;
+ priv->port = serial->port[0];
+ priv->udev = serial->dev;
+
+ /* find our bulk endpoint */
+ intf = serial->interface->altsetting;
+ for (i = 0; i < intf->desc.bNumEndpoints; ++i) {
+ struct usb_endpoint_descriptor *endpoint;
+
+ endpoint = &intf->endpoint[i].desc;
+ if (!usb_endpoint_is_bulk_in(endpoint))
+ continue;
+
+ priv->bulk_read_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!priv->bulk_read_urb) {
+ dev_err(&priv->udev->dev, "out of memory\n");
+ goto error;
+ }
+
+ priv->buffer_size = le16_to_cpu(endpoint->wMaxPacketSize) * 2;
+ priv->bulk_in_buffer = kmalloc(priv->buffer_size, GFP_KERNEL);
+ if (!priv->bulk_in_buffer) {
+ dev_err(&priv->udev->dev, "out of memory\n");
+ goto error;
+ }
+
+ priv->bulk_address = endpoint->bEndpointAddress;
+
+ /* set up our bulk urb */
+ usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev,
+ usb_rcvbulkpipe(priv->udev,
+ endpoint->bEndpointAddress),
+ priv->bulk_in_buffer, priv->buffer_size,
+ opticon_bulk_callback, priv);
+
+ bulk_in_found = true;
+ break;
+ }
+
+ if (!bulk_in_found) {
+ dev_err(&priv->udev->dev,
+ "Error - the proper endpoints were not found!\n");
+ goto error;
+ }
+
+ usb_set_serial_data(serial, priv);
+ return 0;
+
+error:
+ usb_free_urb(priv->bulk_read_urb);
+ kfree(priv->bulk_in_buffer);
+ kfree(priv);
+ return retval;
+}
+
+static void opticon_shutdown(struct usb_serial *serial)
+{
+ struct opticon_private *priv = usb_get_serial_data(serial);
+
+ dbg("%s", __func__);
+
+ usb_kill_urb(priv->bulk_read_urb);
+ usb_free_urb(priv->bulk_read_urb);
+ kfree(priv->bulk_in_buffer);
+ kfree(priv);
+ usb_set_serial_data(serial, NULL);
+}
+
+
+static struct usb_driver opticon_driver = {
+ .name = "opticon",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
+static struct usb_serial_driver opticon_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "opticon",
+ },
+ .id_table = id_table,
+ .usb_driver = &opticon_driver,
+ .num_ports = 1,
+ .attach = opticon_startup,
+ .open = opticon_open,
+ .close = opticon_close,
+ .shutdown = opticon_shutdown,
+ .throttle = opticon_throttle,
+ .unthrottle = opticon_unthrottle,
+};
+
+static int __init opticon_init(void)
+{
+ int retval;
+
+ retval = usb_serial_register(&opticon_device);
+ if (retval)
+ return retval;
+ retval = usb_register(&opticon_driver);
+ if (retval)
+ usb_serial_deregister(&opticon_device);
+ return retval;
+}
+
+static void __exit opticon_exit(void)
+{
+ usb_deregister(&opticon_driver);
+ usb_serial_deregister(&opticon_device);
+}
+
+module_init(opticon_init);
+module_exit(opticon_exit);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 809697b3c7fc..5ed183477aaf 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -522,9 +522,9 @@ static int debug;
/* per port private data */
#define N_IN_URB 4
-#define N_OUT_URB 1
+#define N_OUT_URB 4
#define IN_BUFLEN 4096
-#define OUT_BUFLEN 128
+#define OUT_BUFLEN 4096
struct option_port_private {
/* Input endpoints and buffer for this port */
@@ -654,10 +654,6 @@ static int option_write(struct tty_struct *tty, struct usb_serial_port *port,
usb_unlink_urb(this_urb);
continue;
}
- if (this_urb->status != 0)
- dbg("usb_write %p failed (err=%d)",
- this_urb, this_urb->status);
-
dbg("%s: endpoint %d buf %d", __func__,
usb_pipeendpoint(this_urb->pipe), i);
@@ -669,8 +665,7 @@ static int option_write(struct tty_struct *tty, struct usb_serial_port *port,
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err) {
dbg("usb_submit_urb %p (write bulk) failed "
- "(%d, has %d)", this_urb,
- err, this_urb->status);
+ "(%d)", this_urb, err);
clear_bit(i, &portdata->out_busy);
continue;
}
diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c
new file mode 100644
index 000000000000..951ea0c6ba77
--- /dev/null
+++ b/drivers/usb/serial/siemens_mpi.c
@@ -0,0 +1,77 @@
+/*
+ * Siemens USB-MPI Serial USB driver
+ *
+ * Copyright (C) 2005 Thomas Hergenhahn <thomas.hergenhahn@suse.de>
+ * Copyright (C) 2005,2008 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+/* Version Information */
+#define DRIVER_VERSION "Version 0.1 09/26/2005"
+#define DRIVER_AUTHOR "Thomas Hergenhahn@web.de http://libnodave.sf.net"
+#define DRIVER_DESC "Driver for Siemens USB/MPI adapter"
+
+
+static struct usb_device_id id_table[] = {
+ /* Vendor and product id for 6ES7-972-0CB20-0XA0 */
+ { USB_DEVICE(0x908, 0x0004) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver siemens_usb_mpi_driver = {
+ .name = "siemens_mpi",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+};
+
+static struct usb_serial_driver siemens_usb_mpi_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "siemens_mpi",
+ },
+ .id_table = id_table,
+ .num_ports = 1,
+};
+
+static int __init siemens_usb_mpi_init(void)
+{
+ int retval;
+
+ retval = usb_serial_register(&siemens_usb_mpi_device);
+ if (retval)
+ goto failed_usb_serial_register;
+ retval = usb_register(&siemens_usb_mpi_driver);
+ if (retval)
+ goto failed_usb_register;
+ printk(KERN_INFO DRIVER_DESC "\n");
+ printk(KERN_INFO DRIVER_VERSION " " DRIVER_AUTHOR "\n");
+ return retval;
+failed_usb_register:
+ usb_serial_deregister(&siemens_usb_mpi_device);
+failed_usb_serial_register:
+ return retval;
+}
+
+static void __exit siemens_usb_mpi_exit(void)
+{
+ usb_deregister(&siemens_usb_mpi_driver);
+ usb_serial_deregister(&siemens_usb_mpi_device);
+}
+
+module_init(siemens_usb_mpi_init);
+module_exit(siemens_usb_mpi_exit);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index a65bc2bd8e71..5e7528cc81a8 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -709,21 +709,20 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
unsigned long flags;
int i;
- int result;
- u8 status = 0;
+ int result = urb->status;
+ u8 status;
char tty_flag;
- dev_dbg(&port->dev, "start, urb->status = %d, "
- "urb->actual_length = %d\n,", urb->status, urb->actual_length);
+ dev_dbg(&port->dev, "start, result = %d, urb->actual_length = %d\n,",
+ result, urb->actual_length);
/* check the urb status */
- if (urb->status) {
+ if (result) {
if (!port->port.count)
return;
- if (urb->status == -EPROTO) {
+ if (result == -EPROTO) {
/* spcp8x5 mysteriously fails with -EPROTO */
/* reschedule the read */
- urb->status = 0;
urb->dev = port->serial->dev;
result = usb_submit_urb(urb , GFP_ATOMIC);
if (result)
@@ -833,8 +832,9 @@ static void spcp8x5_write_bulk_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
int result;
+ int status = urb->status;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -843,14 +843,14 @@ static void spcp8x5_write_bulk_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dev_dbg(&port->dev, "urb shutting down with status: %d\n",
- urb->status);
+ status);
priv->write_urb_in_use = 0;
return;
default:
/* error in the urb, so we have to resubmit it */
dbg("%s - Overflow in write", __func__);
dbg("%s - nonzero write bulk status received: %d",
- __func__, urb->status);
+ __func__, status);
port->write_urb->transfer_buffer_length = 1;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 01d0c70d60e9..3cf41df302d7 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -145,7 +145,7 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command,
static int ti_write_byte(struct ti_device *tdev, unsigned long addr,
__u8 mask, __u8 byte);
-static int ti_download_firmware(struct ti_device *tdev, int type);
+static int ti_download_firmware(struct ti_device *tdev);
/* circular buffer */
static struct circ_buf *ti_buf_alloc(void);
@@ -176,9 +176,14 @@ static unsigned int product_5052_count;
/* the array dimension is the number of default entries plus */
/* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */
/* null entry */
-static struct usb_device_id ti_id_table_3410[1+TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_3410[7+TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_NO_FW_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_EDGE_PRODUCT_ID) },
};
static struct usb_device_id ti_id_table_5052[4+TI_EXTRA_VID_PID_COUNT+1] = {
@@ -188,9 +193,14 @@ static struct usb_device_id ti_id_table_5052[4+TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
};
-static struct usb_device_id ti_id_table_combined[] = {
+static struct usb_device_id ti_id_table_combined[6+2*TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_NO_FW_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_PRODUCT_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_EDGE_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) },
@@ -272,6 +282,9 @@ MODULE_LICENSE("GPL");
MODULE_FIRMWARE("ti_3410.fw");
MODULE_FIRMWARE("ti_5052.fw");
+MODULE_FIRMWARE("mts_cdma.fw");
+MODULE_FIRMWARE("mts_gsm.fw");
+MODULE_FIRMWARE("mts_edge.fw");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Enable debugging, 0=no, 1=yes");
@@ -304,21 +317,28 @@ MODULE_DEVICE_TABLE(usb, ti_id_table_combined);
static int __init ti_init(void)
{
- int i, j;
+ int i, j, c;
int ret;
/* insert extra vendor and product ids */
+ c = ARRAY_SIZE(ti_id_table_combined) - 2 * TI_EXTRA_VID_PID_COUNT - 1;
j = ARRAY_SIZE(ti_id_table_3410) - TI_EXTRA_VID_PID_COUNT - 1;
- for (i = 0; i < min(vendor_3410_count, product_3410_count); i++, j++) {
+ for (i = 0; i < min(vendor_3410_count, product_3410_count); i++, j++, c++) {
ti_id_table_3410[j].idVendor = vendor_3410[i];
ti_id_table_3410[j].idProduct = product_3410[i];
ti_id_table_3410[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+ ti_id_table_combined[c].idVendor = vendor_3410[i];
+ ti_id_table_combined[c].idProduct = product_3410[i];
+ ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
}
j = ARRAY_SIZE(ti_id_table_5052) - TI_EXTRA_VID_PID_COUNT - 1;
- for (i = 0; i < min(vendor_5052_count, product_5052_count); i++, j++) {
+ for (i = 0; i < min(vendor_5052_count, product_5052_count); i++, j++, c++) {
ti_id_table_5052[j].idVendor = vendor_5052[i];
ti_id_table_5052[j].idProduct = product_5052[i];
ti_id_table_5052[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+ ti_id_table_combined[c].idVendor = vendor_5052[i];
+ ti_id_table_combined[c].idProduct = product_5052[i];
+ ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
}
ret = usb_serial_register(&ti_1port_device);
@@ -390,11 +410,7 @@ static int ti_startup(struct usb_serial *serial)
/* if we have only 1 configuration, download firmware */
if (dev->descriptor.bNumConfigurations == 1) {
- if (tdev->td_is_3410)
- status = ti_download_firmware(tdev, 3410);
- else
- status = ti_download_firmware(tdev, 5052);
- if (status)
+ if ((status = ti_download_firmware(tdev)) != 0)
goto free_tdev;
/* 3410 must be reset, 5052 resets itself */
@@ -1671,9 +1687,9 @@ static int ti_do_download(struct usb_device *dev, int pipe,
return status;
}
-static int ti_download_firmware(struct ti_device *tdev, int type)
+static int ti_download_firmware(struct ti_device *tdev)
{
- int status = -ENOMEM;
+ int status;
int buffer_size;
__u8 *buffer;
struct usb_device *dev = tdev->td_serial->dev;
@@ -1681,9 +1697,34 @@ static int ti_download_firmware(struct ti_device *tdev, int type)
tdev->td_serial->port[0]->bulk_out_endpointAddress);
const struct firmware *fw_p;
char buf[32];
- sprintf(buf, "ti_usb-%d.bin", type);
- if (request_firmware(&fw_p, buf, &dev->dev)) {
+ /* try ID specific firmware first, then try generic firmware */
+ sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor,
+ dev->descriptor.idProduct);
+ if ((status = request_firmware(&fw_p, buf, &dev->dev)) != 0) {
+ buf[0] = '\0';
+ if (dev->descriptor.idVendor == MTS_VENDOR_ID) {
+ switch (dev->descriptor.idProduct) {
+ case MTS_CDMA_PRODUCT_ID:
+ strcpy(buf, "mts_cdma.fw");
+ break;
+ case MTS_GSM_PRODUCT_ID:
+ strcpy(buf, "mts_gsm.fw");
+ break;
+ case MTS_EDGE_PRODUCT_ID:
+ strcpy(buf, "mts_edge.fw");
+ break;
+ }
+ }
+ if (buf[0] == '\0') {
+ if (tdev->td_is_3410)
+ strcpy(buf, "ti_3410.fw");
+ else
+ strcpy(buf, "ti_5052.fw");
+ }
+ status = request_firmware(&fw_p, buf, &dev->dev);
+ }
+ if (status) {
dev_err(&dev->dev, "%s - firmware not found\n", __func__);
return -ENOENT;
}
@@ -1699,6 +1740,8 @@ static int ti_download_firmware(struct ti_device *tdev, int type)
memset(buffer + fw_p->size, 0xff, buffer_size - fw_p->size);
status = ti_do_download(dev, pipe, buffer, fw_p->size);
kfree(buffer);
+ } else {
+ status = -ENOMEM;
}
release_firmware(fw_p);
if (status) {
diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h
index b5541bf991ba..7e4752fbf232 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.h
+++ b/drivers/usb/serial/ti_usb_3410_5052.h
@@ -34,6 +34,14 @@
#define TI_5052_EEPROM_PRODUCT_ID 0x505A /* EEPROM, no firmware */
#define TI_5052_FIRMWARE_PRODUCT_ID 0x505F /* firmware is running */
+/* Multi-Tech vendor and product ids */
+#define MTS_VENDOR_ID 0x06E0
+#define MTS_GSM_NO_FW_PRODUCT_ID 0xF108
+#define MTS_CDMA_NO_FW_PRODUCT_ID 0xF109
+#define MTS_CDMA_PRODUCT_ID 0xF110
+#define MTS_GSM_PRODUCT_ID 0xF111
+#define MTS_EDGE_PRODUCT_ID 0xF112
+
/* Commands */
#define TI_GET_VERSION 0x01
#define TI_GET_PORT_STATUS 0x02
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 080ade223d53..cfcfd5ab06ce 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -511,9 +511,6 @@ static void usb_serial_port_work(struct work_struct *work)
dbg("%s - port %d", __func__, port->number);
- if (!port)
- return;
-
tty = tty_port_tty_get(&port->port);
if (!tty)
return;
diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index fc5d9952b03b..6c9cbb59552a 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -31,7 +31,7 @@ static struct usb_driver debug_driver = {
.no_dynamic_id = 1,
};
-int usb_debug_open(struct tty_struct *tty, struct usb_serial_port *port,
+static int usb_debug_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
{
port->bulk_out_size = USB_DEBUG_MAX_PACKET_SIZE;
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index c68b738900bd..9df6887b91f6 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -61,13 +61,6 @@ config USB_STORAGE_ISD200
- CyQ've CQ8060A CDRW drive
- Planex eXtreme Drive RX-25HU USB-IDE cable (not model RX-25U)
-config USB_STORAGE_DPCM
- bool "Microtech/ZiO! CompactFlash/SmartMedia support"
- depends on USB_STORAGE
- help
- Say Y here to support the Microtech/ZiO! CompactFlash reader.
- There is a web page at <http://www.ziocorp.com/products/>.
-
config USB_STORAGE_USBAT
bool "USBAT/USBAT02-based storage support"
depends on USB_STORAGE
@@ -90,12 +83,12 @@ config USB_STORAGE_USBAT
- Sandisk ImageMate SDDR-05b
config USB_STORAGE_SDDR09
- bool "SanDisk SDDR-09 (and other SmartMedia) support"
+ bool "SanDisk SDDR-09 (and other SmartMedia, including DPCM) support"
depends on USB_STORAGE
help
Say Y here to include additional code to support the Sandisk SDDR-09
SmartMedia reader in the USB Mass Storage driver.
- Also works for the Microtech Zio! SmartMedia reader.
+ Also works for the Microtech Zio! CompactFlash/SmartMedia reader.
config USB_STORAGE_SDDR55
bool "SanDisk SDDR-55 SmartMedia support"
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
index 7f8beb5366ae..b32069313390 100644
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -14,7 +14,6 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_USBAT) += shuttle_usbat.o
usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR09) += sddr09.o
usb-storage-obj-$(CONFIG_USB_STORAGE_SDDR55) += sddr55.o
usb-storage-obj-$(CONFIG_USB_STORAGE_FREECOM) += freecom.o
-usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM) += dpcm.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200) += isd200.o
usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB) += datafab.o
usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o
@@ -24,7 +23,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA) += karma.o
usb-storage-obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += cypress_atacb.o
usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
- initializers.o sierra_ms.o $(usb-storage-obj-y)
+ initializers.o sierra_ms.o option_ms.o $(usb-storage-obj-y)
ifneq ($(CONFIG_USB_LIBUSUAL),)
obj-$(CONFIG_USB) += libusual.o
diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c
deleted file mode 100644
index 939923471af4..000000000000
--- a/drivers/usb/storage/dpcm.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
- *
- * DPCM driver v0.1:
- *
- * First release
- *
- * Current development and maintenance by:
- * (c) 2000 Brian Webb (webbb@earthlink.net)
- *
- * This device contains both a CompactFlash card reader, which
- * uses the Control/Bulk w/o Interrupt protocol and
- * a SmartMedia card reader that uses the same protocol
- * as the SDDR09.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-
-#include "usb.h"
-#include "transport.h"
-#include "protocol.h"
-#include "debug.h"
-#include "dpcm.h"
-#include "sddr09.h"
-
-/*
- * Transport for the Microtech DPCM-USB
- *
- */
-int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
-{
- int ret;
-
- if (srb == NULL)
- return USB_STOR_TRANSPORT_ERROR;
-
- US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
-
- switch (srb->device->lun) {
- case 0:
-
- /*
- * LUN 0 corresponds to the CompactFlash card reader.
- */
- ret = usb_stor_CB_transport(srb, us);
- break;
-
-#ifdef CONFIG_USB_STORAGE_SDDR09
- case 1:
-
- /*
- * LUN 1 corresponds to the SmartMedia card reader.
- */
-
- /*
- * Set the LUN to 0 (just in case).
- */
- srb->device->lun = 0; us->srb->device->lun = 0;
- ret = sddr09_transport(srb, us);
- srb->device->lun = 1; us->srb->device->lun = 1;
- break;
-
-#endif
-
- default:
- US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
- ret = USB_STOR_TRANSPORT_ERROR;
- break;
- }
- return ret;
-}
diff --git a/drivers/usb/storage/dpcm.h b/drivers/usb/storage/dpcm.h
deleted file mode 100644
index e7b7b0f120d7..000000000000
--- a/drivers/usb/storage/dpcm.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
- *
- * DPCM driver v0.1:
- *
- * First release
- *
- * Current development and maintenance by:
- * (c) 2000 Brian Webb (webbb@earthlink.net)
- *
- * See dpcm.c for more explanation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _MICROTECH_DPCM_USB_H
-#define _MICROTECH_DPCM_USB_H
-
-extern int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us);
-
-#endif
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
index d617e8ae6b00..f970b27ba308 100644
--- a/drivers/usb/storage/libusual.c
+++ b/drivers/usb/storage/libusual.c
@@ -46,6 +46,12 @@ static int usu_probe_thread(void *arg);
{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax), \
.driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+#define COMPLIANT_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
+ vendorName, productName, useProtocol, useTransport, \
+ initFunction, flags) \
+{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
+ .driver_info = (flags) }
+
#define USUAL_DEV(useProto, useTrans, useType) \
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \
.driver_info = ((useType)<<24) }
@@ -57,6 +63,7 @@ struct usb_device_id storage_usb_ids [] = {
#undef USUAL_DEV
#undef UNUSUAL_DEV
+#undef COMPLIANT_DEV
MODULE_DEVICE_TABLE(usb, storage_usb_ids);
EXPORT_SYMBOL_GPL(storage_usb_ids);
diff --git a/drivers/usb/storage/option_ms.c b/drivers/usb/storage/option_ms.c
new file mode 100644
index 000000000000..353f922939a4
--- /dev/null
+++ b/drivers/usb/storage/option_ms.c
@@ -0,0 +1,147 @@
+/*
+ * Driver for Option High Speed Mobile Devices.
+ *
+ * (c) 2008 Dan Williams <dcbw@redhat.com>
+ *
+ * Inspiration taken from sierra_ms.c by Kevin Lloyd <klloyd@sierrawireless.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/usb.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "option_ms.h"
+#include "debug.h"
+
+#define ZCD_FORCE_MODEM 0x01
+#define ZCD_ALLOW_MS 0x02
+
+static unsigned int option_zero_cd = ZCD_FORCE_MODEM;
+module_param(option_zero_cd, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(option_zero_cd, "ZeroCD mode (1=Force Modem (default),"
+ " 2=Allow CD-Rom");
+
+#define RESPONSE_LEN 1024
+
+static int option_rezero(struct us_data *us, int ep_in, int ep_out)
+{
+ const unsigned char rezero_msg[] = {
+ 0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12,
+ 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ char *buffer;
+ int result;
+
+ US_DEBUGP("Option MS: %s", "DEVICE MODE SWITCH\n");
+
+ buffer = kzalloc(RESPONSE_LEN, GFP_KERNEL);
+ if (buffer == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
+
+ memcpy(buffer, rezero_msg, sizeof (rezero_msg));
+ result = usb_stor_bulk_transfer_buf(us,
+ usb_sndbulkpipe(us->pusb_dev, ep_out),
+ buffer, sizeof (rezero_msg), NULL);
+ if (result != USB_STOR_XFER_GOOD) {
+ result = USB_STOR_XFER_ERROR;
+ goto out;
+ }
+
+ /* Some of the devices need to be asked for a response, but we don't
+ * care what that response is.
+ */
+ result = usb_stor_bulk_transfer_buf(us,
+ usb_sndbulkpipe(us->pusb_dev, ep_out),
+ buffer, RESPONSE_LEN, NULL);
+ result = USB_STOR_XFER_GOOD;
+
+out:
+ kfree(buffer);
+ return result;
+}
+
+int option_ms_init(struct us_data *us)
+{
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint = NULL;
+ u8 ep_in = 0, ep_out = 0;
+ int ep_in_size = 0, ep_out_size = 0;
+ int i, result;
+
+ udev = us->pusb_dev;
+ intf = us->pusb_intf;
+
+ /* Ensure it's really a ZeroCD device; devices that are already
+ * in modem mode return 0xFF for class, subclass, and protocol.
+ */
+ if (udev->descriptor.bDeviceClass != 0 ||
+ udev->descriptor.bDeviceSubClass != 0 ||
+ udev->descriptor.bDeviceProtocol != 0)
+ return USB_STOR_TRANSPORT_GOOD;
+
+ US_DEBUGP("Option MS: option_ms_init called\n");
+
+ /* Find the right mass storage interface */
+ iface_desc = intf->cur_altsetting;
+ if (iface_desc->desc.bInterfaceClass != 0x8 ||
+ iface_desc->desc.bInterfaceSubClass != 0x6 ||
+ iface_desc->desc.bInterfaceProtocol != 0x50) {
+ US_DEBUGP("Option MS: mass storage interface not found, no action "
+ "required\n");
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ /* Find the mass storage bulk endpoints */
+ for (i = 0; i < iface_desc->desc.bNumEndpoints && (!ep_in_size || !ep_out_size); ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_bulk_in(endpoint)) {
+ ep_in = usb_endpoint_num(endpoint);
+ ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ } else if (usb_endpoint_is_bulk_out(endpoint)) {
+ ep_out = usb_endpoint_num(endpoint);
+ ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ }
+ }
+
+ /* Can't find the mass storage endpoints */
+ if (!ep_in_size || !ep_out_size) {
+ US_DEBUGP("Option MS: mass storage endpoints not found, no action "
+ "required\n");
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ /* Force Modem mode */
+ if (option_zero_cd == ZCD_FORCE_MODEM) {
+ US_DEBUGP("Option MS: %s", "Forcing Modem Mode\n");
+ result = option_rezero(us, ep_in, ep_out);
+ if (result != USB_STOR_XFER_GOOD)
+ US_DEBUGP("Option MS: Failed to switch to modem mode.\n");
+ return -EIO;
+ } else if (option_zero_cd == ZCD_ALLOW_MS) {
+ /* Allow Mass Storage mode (keep CD-Rom) */
+ US_DEBUGP("Option MS: %s", "Allowing Mass Storage Mode if device"
+ " requests it\n");
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
diff --git a/drivers/usb/storage/option_ms.h b/drivers/usb/storage/option_ms.h
new file mode 100644
index 000000000000..b6e448cab039
--- /dev/null
+++ b/drivers/usb/storage/option_ms.h
@@ -0,0 +1,4 @@
+#ifndef _OPTION_MS_H_
+#define _OPTION_MS_H_
+extern int option_ms_init(struct us_data *us);
+#endif
diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c
index 3b3357e20ea7..be441d84bc64 100644
--- a/drivers/usb/storage/protocol.c
+++ b/drivers/usb/storage/protocol.c
@@ -56,9 +56,9 @@
* Protocol routines
***********************************************************************/
-void usb_stor_qic157_command(struct scsi_cmnd *srb, struct us_data *us)
+void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us)
{
- /* Pad the ATAPI command with zeros
+ /* Pad the SCSI command with zeros out to 12 bytes
*
* NOTE: This only works because a scsi_cmnd struct field contains
* a unsigned char cmnd[16], so we know we have storage available
@@ -73,26 +73,6 @@ void usb_stor_qic157_command(struct scsi_cmnd *srb, struct us_data *us)
usb_stor_invoke_transport(srb, us);
}
-void usb_stor_ATAPI_command(struct scsi_cmnd *srb, struct us_data *us)
-{
- /* Pad the ATAPI command with zeros
- *
- * NOTE: This only works because a scsi_cmnd struct field contains
- * a unsigned char cmnd[16], so we know we have storage available
- */
-
- /* Pad the ATAPI command with zeros */
- for (; srb->cmd_len<12; srb->cmd_len++)
- srb->cmnd[srb->cmd_len] = 0;
-
- /* set command length to 12 bytes */
- srb->cmd_len = 12;
-
- /* send the command to the transport layer */
- usb_stor_invoke_transport(srb, us);
-}
-
-
void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us)
{
/* fix some commands -- this is a form of mode translation
diff --git a/drivers/usb/storage/protocol.h b/drivers/usb/storage/protocol.h
index 487056ffb516..ffc3e2af0156 100644
--- a/drivers/usb/storage/protocol.h
+++ b/drivers/usb/storage/protocol.h
@@ -40,8 +40,7 @@
#define _PROTOCOL_H_
/* Protocol handling routines */
-extern void usb_stor_ATAPI_command(struct scsi_cmnd*, struct us_data*);
-extern void usb_stor_qic157_command(struct scsi_cmnd*, struct us_data*);
+extern void usb_stor_pad12_command(struct scsi_cmnd*, struct us_data*);
extern void usb_stor_ufi_command(struct scsi_cmnd*, struct us_data*);
extern void usb_stor_transparent_scsi_command(struct scsi_cmnd*,
struct us_data*);
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 09779f6a8179..2a42b862aa9f 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -59,6 +59,13 @@
#include "transport.h"
#include "protocol.h"
+/* Vendor IDs for companies that seem to include the READ CAPACITY bug
+ * in all their devices
+ */
+#define VENDOR_ID_NOKIA 0x0421
+#define VENDOR_ID_NIKON 0x04b0
+#define VENDOR_ID_MOTOROLA 0x22b8
+
/***********************************************************************
* Host functions
***********************************************************************/
@@ -129,11 +136,35 @@ static int slave_configure(struct scsi_device *sdev)
max_sectors);
}
+ /* Some USB host controllers can't do DMA; they have to use PIO.
+ * They indicate this by setting their dma_mask to NULL. For
+ * such controllers we need to make sure the block layer sets
+ * up bounce buffers in addressable memory.
+ */
+ if (!us->pusb_dev->bus->controller->dma_mask)
+ blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_HIGH);
+
/* We can't put these settings in slave_alloc() because that gets
* called before the device type is known. Consequently these
* settings can't be overridden via the scsi devinfo mechanism. */
if (sdev->type == TYPE_DISK) {
+ /* Some vendors seem to put the READ CAPACITY bug into
+ * all their devices -- primarily makers of cell phones
+ * and digital cameras. Since these devices always use
+ * flash media and can be expected to have an even number
+ * of sectors, we will always enable the CAPACITY_HEURISTICS
+ * flag unless told otherwise. */
+ switch (le16_to_cpu(us->pusb_dev->descriptor.idVendor)) {
+ case VENDOR_ID_NOKIA:
+ case VENDOR_ID_NIKON:
+ case VENDOR_ID_MOTOROLA:
+ if (!(us->fflags & (US_FL_FIX_CAPACITY |
+ US_FL_CAPACITY_OK)))
+ us->fflags |= US_FL_CAPACITY_HEURISTICS;
+ break;
+ }
+
/* Disk-type devices use MODE SENSE(6) if the protocol
* (SubClass) is Transparent SCSI, otherwise they use
* MODE SENSE(10). */
@@ -170,6 +201,10 @@ static int slave_configure(struct scsi_device *sdev)
if (us->fflags & US_FL_CAPACITY_HEURISTICS)
sdev->guess_capacity = 1;
+ /* assume SPC3 or latter devices support sense size > 18 */
+ if (sdev->scsi_level > SCSI_SPC_2)
+ us->fflags |= US_FL_SANE_SENSE;
+
/* Some devices report a SCSI revision level above 2 but are
* unable to handle the REPORT LUNS command (for which
* support is mandatory at level 3). Since we already have
@@ -196,6 +231,14 @@ static int slave_configure(struct scsi_device *sdev)
* 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;
+
+ /* Enable last-sector hacks for single-target devices using
+ * the Bulk-only transport, unless we already know the
+ * capacity will be decremented or is correct. */
+ if (!(us->fflags & (US_FL_FIX_CAPACITY | US_FL_CAPACITY_OK |
+ US_FL_SCM_MULT_TARG)) &&
+ us->protocol == US_PR_BULK)
+ us->use_last_sector_hacks = 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 c5a54b872c24..531ae5c5abf3 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -45,6 +45,7 @@
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
#include "usb.h"
#include "transport.h"
@@ -1446,6 +1447,48 @@ usb_stor_sddr09_dpcm_init(struct us_data *us) {
}
/*
+ * Transport for the Microtech DPCM-USB
+ */
+int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+ int ret;
+
+ US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
+
+ switch (srb->device->lun) {
+ case 0:
+
+ /*
+ * LUN 0 corresponds to the CompactFlash card reader.
+ */
+ ret = usb_stor_CB_transport(srb, us);
+ break;
+
+ case 1:
+
+ /*
+ * LUN 1 corresponds to the SmartMedia card reader.
+ */
+
+ /*
+ * Set the LUN to 0 (just in case).
+ */
+ srb->device->lun = 0;
+ ret = sddr09_transport(srb, us);
+ srb->device->lun = 1;
+ break;
+
+ default:
+ US_DEBUGP("dpcm_transport: Invalid LUN %d\n",
+ srb->device->lun);
+ ret = USB_STOR_TRANSPORT_ERROR;
+ break;
+ }
+ return ret;
+}
+
+
+/*
* Transport for the Sandisk SDDR-09
*/
int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us)
diff --git a/drivers/usb/storage/sddr09.h b/drivers/usb/storage/sddr09.h
index e50033ad7b19..b701172e12e3 100644
--- a/drivers/usb/storage/sddr09.h
+++ b/drivers/usb/storage/sddr09.h
@@ -28,8 +28,11 @@
/* Sandisk SDDR-09 stuff */
extern int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us);
+extern int usb_stor_sddr09_init(struct us_data *us);
+
+/* Microtech DPCM-USB stuff */
+extern int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us);
extern int usb_stor_sddr09_dpcm_init(struct us_data *us);
-extern int usb_stor_sddr09_init(struct us_data *us);
#endif
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 79108d5d3171..1d5438e6363b 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -57,6 +57,9 @@
#include "scsiglue.h"
#include "debug.h"
+#include <linux/blkdev.h>
+#include "../../scsi/sd.h"
+
/***********************************************************************
* Data transfer routines
@@ -511,6 +514,110 @@ int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,
* Transport routines
***********************************************************************/
+/* There are so many devices that report the capacity incorrectly,
+ * this routine was written to counteract some of the resulting
+ * problems.
+ */
+static void last_sector_hacks(struct us_data *us, struct scsi_cmnd *srb)
+{
+ struct gendisk *disk;
+ struct scsi_disk *sdkp;
+ u32 sector;
+
+ /* To Report "Medium Error: Record Not Found */
+ static unsigned char record_not_found[18] = {
+ [0] = 0x70, /* current error */
+ [2] = MEDIUM_ERROR, /* = 0x03 */
+ [7] = 0x0a, /* additional length */
+ [12] = 0x14 /* Record Not Found */
+ };
+
+ /* If last-sector problems can't occur, whether because the
+ * capacity was already decremented or because the device is
+ * known to report the correct capacity, then we don't need
+ * to do anything.
+ */
+ if (!us->use_last_sector_hacks)
+ return;
+
+ /* Was this command a READ(10) or a WRITE(10)? */
+ if (srb->cmnd[0] != READ_10 && srb->cmnd[0] != WRITE_10)
+ goto done;
+
+ /* Did this command access the last sector? */
+ sector = (srb->cmnd[2] << 24) | (srb->cmnd[3] << 16) |
+ (srb->cmnd[4] << 8) | (srb->cmnd[5]);
+ disk = srb->request->rq_disk;
+ if (!disk)
+ goto done;
+ sdkp = scsi_disk(disk);
+ if (!sdkp)
+ goto done;
+ if (sector + 1 != sdkp->capacity)
+ goto done;
+
+ if (srb->result == SAM_STAT_GOOD && scsi_get_resid(srb) == 0) {
+
+ /* The command succeeded. If the capacity is odd
+ * (i.e., if the sector number is even) then the
+ * "always-even" heuristic would be wrong for this
+ * device. Issue a WARN() so that the kerneloops.org
+ * project will be notified and we will then know to
+ * mark the device with a CAPACITY_OK flag. Hopefully
+ * this will occur for only a few devices.
+ *
+ * Use the sign of us->last_sector_hacks to tell whether
+ * the warning has already been issued; we don't need
+ * more than one warning per device.
+ */
+ if (!(sector & 1) && us->use_last_sector_hacks > 0) {
+ unsigned vid = le16_to_cpu(
+ us->pusb_dev->descriptor.idVendor);
+ unsigned pid = le16_to_cpu(
+ us->pusb_dev->descriptor.idProduct);
+ unsigned rev = le16_to_cpu(
+ us->pusb_dev->descriptor.bcdDevice);
+
+ WARN(1, "%s: Successful last sector success at %u, "
+ "device %04x:%04x:%04x\n",
+ sdkp->disk->disk_name, sector,
+ vid, pid, rev);
+ us->use_last_sector_hacks = -1;
+ }
+
+ } else {
+ /* The command failed. Allow up to 3 retries in case this
+ * is some normal sort of failure. After that, assume the
+ * capacity is wrong and we're trying to access the sector
+ * beyond the end. Replace the result code and sense data
+ * with values that will cause the SCSI core to fail the
+ * command immediately, instead of going into an infinite
+ * (or even just a very long) retry loop.
+ */
+ if (++us->last_sector_retries < 3)
+ return;
+ srb->result = SAM_STAT_CHECK_CONDITION;
+ memcpy(srb->sense_buffer, record_not_found,
+ sizeof(record_not_found));
+
+ /* In theory we might want to issue a WARN() here if the
+ * capacity is even, since it could indicate the device
+ * has the READ CAPACITY bug _and_ the real capacity is
+ * odd. But it could also indicate that the device
+ * simply can't access its last sector, a failure mode
+ * which is surprisingly common. So no warning.
+ */
+ }
+
+ done:
+ /* Don't reset the retry counter for TEST UNIT READY commands,
+ * because they get issued after device resets which might be
+ * caused by a failed last-sector access.
+ */
+ if (srb->cmnd[0] != TEST_UNIT_READY)
+ us->last_sector_retries = 0;
+}
+
/* Invoke the transport and basic error-handling/recovery methods
*
* This is used by the protocol layers to actually send the message to
@@ -544,6 +651,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* if the transport provided its own sense data, don't auto-sense */
if (result == USB_STOR_TRANSPORT_NO_SENSE) {
srb->result = SAM_STAT_CHECK_CONDITION;
+ last_sector_hacks(us, srb);
return;
}
@@ -579,6 +687,20 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
}
/*
+ * Determine if this device is SAT by seeing if the
+ * command executed successfully. Otherwise we'll have
+ * to wait for at least one CHECK_CONDITION to determine
+ * SANE_SENSE support
+ */
+ if ((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) &&
+ result == USB_STOR_TRANSPORT_GOOD &&
+ !(us->fflags & US_FL_SANE_SENSE) &&
+ !(srb->cmnd[2] & 0x20)) {
+ US_DEBUGP("-- SAT supported, increasing auto-sense\n");
+ us->fflags |= US_FL_SANE_SENSE;
+ }
+
+ /*
* A short transfer on a command where we don't expect it
* is unusual, but it doesn't mean we need to auto-sense.
*/
@@ -595,10 +717,15 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
if (need_auto_sense) {
int temp_result;
struct scsi_eh_save ses;
+ int sense_size = US_SENSE_SIZE;
+
+ /* device supports and needs bigger sense buffer */
+ if (us->fflags & US_FL_SANE_SENSE)
+ sense_size = ~0;
US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
- scsi_eh_prep_cmnd(srb, &ses, NULL, 0, US_SENSE_SIZE);
+ scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size);
/* FIXME: we must do the protocol translation here */
if (us->subclass == US_SC_RBC || us->subclass == US_SC_SCSI ||
@@ -632,6 +759,25 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
return;
}
+ /* If the sense data returned is larger than 18-bytes then we
+ * assume this device supports requesting more in the future.
+ * The response code must be 70h through 73h inclusive.
+ */
+ if (srb->sense_buffer[7] > (US_SENSE_SIZE - 8) &&
+ !(us->fflags & US_FL_SANE_SENSE) &&
+ (srb->sense_buffer[0] & 0x7C) == 0x70) {
+ US_DEBUGP("-- SANE_SENSE support enabled\n");
+ us->fflags |= US_FL_SANE_SENSE;
+
+ /* Indicate to the user that we truncated their sense
+ * because we didn't know it supported larger sense.
+ */
+ US_DEBUGP("-- Sense data truncated to %i from %i\n",
+ US_SENSE_SIZE,
+ srb->sense_buffer[7] + 8);
+ srb->sense_buffer[7] = (US_SENSE_SIZE - 8);
+ }
+
US_DEBUGP("-- Result from auto-sense is %d\n", temp_result);
US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n",
srb->sense_buffer[0],
@@ -667,6 +813,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow)
srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24);
+ last_sector_hacks(us, srb);
return;
/* Error and abort processing: try to resynchronize with the device
@@ -694,6 +841,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
us->transport_reset(us);
}
clear_bit(US_FLIDX_RESETTING, &us->dflags);
+ last_sector_hacks(us, srb);
}
/* Stop the current URB transfer */
@@ -718,10 +866,10 @@ void usb_stor_stop_transport(struct us_data *us)
}
/*
- * Control/Bulk/Interrupt transport
+ * Control/Bulk and Control/Bulk/Interrupt transport
*/
-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 = scsi_bufflen(srb);
unsigned int pipe = 0;
@@ -763,6 +911,13 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
}
/* STATUS STAGE */
+
+ /* NOTE: CB does not have a status stage. Silly, I know. So
+ * we have to catch this at a higher level.
+ */
+ if (us->protocol != US_PR_CBI)
+ return USB_STOR_TRANSPORT_GOOD;
+
result = usb_stor_intr_transfer(us, us->iobuf, 2);
US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n",
us->iobuf[0], us->iobuf[1]);
@@ -817,56 +972,6 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us)
}
/*
- * Control/Bulk transport
- */
-int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us)
-{
- unsigned int transfer_length = scsi_bufflen(srb);
- int result;
-
- /* COMMAND STAGE */
- /* let's send the command via the control pipe */
- result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
- US_CBI_ADSC,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
- us->ifnum, srb->cmnd, srb->cmd_len);
-
- /* check the return code for the command */
- US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result);
-
- /* if we stalled the command, it means command failed */
- if (result == USB_STOR_XFER_STALLED) {
- return USB_STOR_TRANSPORT_FAILED;
- }
-
- /* Uh oh... serious problem here */
- if (result != USB_STOR_XFER_GOOD) {
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* DATA STAGE */
- /* transfer the data payload for this command, if one exists*/
- 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_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 */
- if (result == USB_STOR_XFER_STALLED)
- return USB_STOR_TRANSPORT_FAILED;
- if (result > USB_STOR_XFER_STALLED)
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* STATUS STAGE */
- /* NOTE: CB does not have a status stage. Silly, I know. So
- * we have to catch this at a higher level.
- */
- return USB_STOR_TRANSPORT_GOOD;
-}
-
-/*
* Bulk only transport
*/
@@ -1173,10 +1278,9 @@ int usb_stor_Bulk_reset(struct us_data *us)
*/
int usb_stor_port_reset(struct us_data *us)
{
- int result, rc_lock;
+ int result;
- result = rc_lock =
- usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
+ result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
if (result < 0)
US_DEBUGP("unable to lock device for reset: %d\n", result);
else {
@@ -1189,8 +1293,7 @@ int usb_stor_port_reset(struct us_data *us)
US_DEBUGP("usb_reset_device returns %d\n",
result);
}
- if (rc_lock)
- usb_unlock_device(us->pusb_dev);
+ usb_unlock_device(us->pusb_dev);
}
return result;
}
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index e70b88182f0e..242ff5e791a5 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -113,8 +113,6 @@ struct bulk_cs_wrap {
#define US_CBI_ADSC 0
-extern int usb_stor_CBI_transport(struct scsi_cmnd *, struct us_data*);
-
extern int usb_stor_CB_transport(struct scsi_cmnd *, struct us_data*);
extern int usb_stor_CB_reset(struct us_data*);
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index bfcc1fe82518..a7f9513fa19d 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -27,7 +27,8 @@
/* IMPORTANT NOTE: This file must be included in another file which does
* the following thing for it to work:
- * The macro UNUSUAL_DEV() must be defined before this file is included
+ * The UNUSUAL_DEV, COMPLIANT_DEV, and USUAL_DEV macros must be defined
+ * before this file is included.
*/
/* If you edit this file, please try to keep it sorted first by VendorID,
@@ -46,6 +47,12 @@
* <usb-storage@lists.one-eyed-alien.net>
*/
+/* Note: If you add an entry only in order to set the CAPACITY_OK flag,
+ * use the COMPLIANT_DEV macro instead of UNUSUAL_DEV. This is
+ * because such entries mark devices which actually work correctly,
+ * as opposed to devices that do something strangely or wrongly.
+ */
+
/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr>
*/
UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100,
@@ -85,6 +92,13 @@ UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001,
US_SC_8070, US_PR_USBAT, init_usbat_cd, 0),
#endif
+/* Reported by Ben Efros <ben@pc-doctor.com> */
+UNUSUAL_DEV( 0x03f0, 0x070c, 0x0000, 0x0000,
+ "HP",
+ "Personal Media Drive",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_SANE_SENSE ),
+
/* Reported by Grant Grundler <grundler@parisc-linux.org>
* HP r707 camera in "Disk" mode with 2.00.23 or 2.00.24 firmware.
*/
@@ -160,34 +174,6 @@ UNUSUAL_DEV( 0x0421, 0x0019, 0x0592, 0x0592,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_MAX_SECTORS_64 ),
-/* Reported by Filip Joelsson <filip@blueturtle.nu> */
-UNUSUAL_DEV( 0x0421, 0x005d, 0x0001, 0x0600,
- "Nokia",
- "Nokia 3110c",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
-
-/* Reported by Ozan Sener <themgzzy@gmail.com> */
-UNUSUAL_DEV( 0x0421, 0x0060, 0x0551, 0x0551,
- "Nokia",
- "3500c",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
-
-/* Reported by CSECSY Laszlo <boobaa@frugalware.org> */
-UNUSUAL_DEV( 0x0421, 0x0063, 0x0001, 0x0601,
- "Nokia",
- "Nokia 3109c",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
-
-/* Patch for Nokia 5310 capacity */
-UNUSUAL_DEV( 0x0421, 0x006a, 0x0000, 0x0701,
- "Nokia",
- "5310",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
-
/* Reported by Mario Rettig <mariorettig@web.de> */
UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x0100,
"Nokia",
@@ -253,35 +239,6 @@ UNUSUAL_DEV( 0x0421, 0x0495, 0x0370, 0x0370,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_MAX_SECTORS_64 ),
-/* Reported by Cedric Godin <cedric@belbone.be> */
-UNUSUAL_DEV( 0x0421, 0x04b9, 0x0500, 0x0551,
- "Nokia",
- "5300",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
-
-/* Reported by Richard Nauber <RichardNauber@web.de> */
-UNUSUAL_DEV( 0x0421, 0x04fa, 0x0550, 0x0660,
- "Nokia",
- "6300",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
-
-/* Patch for Nokia 5310 capacity */
-UNUSUAL_DEV( 0x0421, 0x006a, 0x0000, 0x0591,
- "Nokia",
- "5310",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
-
-/* Submitted by Ricky Wong Yung Fei <evilbladewarrior@gmail.com> */
-/* Nokia 7610 Supernova - Too many sectors reported in usb storage mode */
-UNUSUAL_DEV( 0x0421, 0x00f5, 0x0000, 0x0470,
- "Nokia",
- "7610 Supernova",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY ),
-
/* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210,
"SMSC",
@@ -289,11 +246,17 @@ UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
-#ifdef CONFIG_USB_STORAGE_DPCM
+#ifdef CONFIG_USB_STORAGE_SDDR09
UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100,
"Microtech",
"CameraMate (DPCM_USB)",
US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ),
+#else
+UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100,
+ "Microtech",
+ "CameraMate",
+ US_SC_SCSI, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN ),
#endif
/* Patch submitted by Daniel Drake <dsd@gentoo.org>
@@ -388,6 +351,15 @@ UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001,
"DVD-CAM DZ-MV100A Camcorder",
US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN),
+/* BENQ DC5330
+ * Reported by Manuel Fombuena <mfombuena@ya.com> and
+ * Frank Copeland <fjc@thingy.apana.org.au> */
+UNUSUAL_DEV( 0x04a5, 0x3010, 0x0100, 0x0100,
+ "Tekom Technologies, Inc",
+ "300_CAMERA",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
/* Patch for Nikon coolpix 2000
* Submitted by Fabien Cosse <fabien.cosse@wanadoo.fr>*/
UNUSUAL_DEV( 0x04b0, 0x0301, 0x0010, 0x0010,
@@ -396,83 +368,6 @@ UNUSUAL_DEV( 0x04b0, 0x0301, 0x0010, 0x0010,
US_SC_DEVICE, US_PR_DEVICE,NULL,
US_FL_NOT_LOCKABLE ),
-/* Reported by Stefan de Konink <skinkie@xs4all.nl> */
-UNUSUAL_DEV( 0x04b0, 0x0401, 0x0200, 0x0200,
- "NIKON",
- "NIKON DSC D100",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
-
-/* Reported by Tobias Kunze Briseno <t-linux@fictive.com> */
-UNUSUAL_DEV( 0x04b0, 0x0403, 0x0200, 0x0200,
- "NIKON",
- "NIKON DSC D2H",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
-
-/* Reported by Milinevsky Dmitry <niam.niam@gmail.com> */
-UNUSUAL_DEV( 0x04b0, 0x0409, 0x0100, 0x0100,
- "NIKON",
- "NIKON DSC D50",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
-
-/* Reported by Andreas Bockhold <andreas@bockionline.de> */
-UNUSUAL_DEV( 0x04b0, 0x0405, 0x0100, 0x0100,
- "NIKON",
- "NIKON DSC D70",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
-
-/* Reported by Jamie Kitson <jamie@staberinde.fsnet.co.uk> */
-UNUSUAL_DEV( 0x04b0, 0x040d, 0x0100, 0x0100,
- "NIKON",
- "NIKON DSC D70s",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
-
-/* Reported by Graber and Mike Pagano <mpagano-kernel@mpagano.com> */
-UNUSUAL_DEV( 0x04b0, 0x040f, 0x0100, 0x0200,
- "NIKON",
- "NIKON DSC D200",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
-
-/* Reported by Emil Larsson <emil@swip.net> */
-UNUSUAL_DEV( 0x04b0, 0x0411, 0x0100, 0x0111,
- "NIKON",
- "NIKON DSC D80",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
-
-/* Reported by Ortwin Glueck <odi@odi.ch> */
-UNUSUAL_DEV( 0x04b0, 0x0413, 0x0110, 0x0111,
- "NIKON",
- "NIKON DSC D40",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
-
-/* Reported by Paul Check <paul@openstreet.com> */
-UNUSUAL_DEV( 0x04b0, 0x0415, 0x0100, 0x0100,
- "NIKON",
- "NIKON DSC D2Xs",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
-
-/* Reported by Shan Destromp (shansan@gmail.com) */
-UNUSUAL_DEV( 0x04b0, 0x0417, 0x0100, 0x0100,
- "NIKON",
- "NIKON DSC D40X",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
-
-/* Reported by paul ready <lxtwin@homecall.co.uk> */
-UNUSUAL_DEV( 0x04b0, 0x0419, 0x0100, 0x0200,
- "NIKON",
- "NIKON DSC D300",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
-
/* Reported by Doug Maxey (dwm@austin.ibm.com) */
UNUSUAL_DEV( 0x04b3, 0x4001, 0x0110, 0x0110,
"IBM",
@@ -480,15 +375,6 @@ UNUSUAL_DEV( 0x04b3, 0x4001, 0x0110, 0x0110,
US_SC_DEVICE, US_PR_CB, NULL,
US_FL_MAX_SECTORS_MIN),
-/* BENQ DC5330
- * Reported by Manuel Fombuena <mfombuena@ya.com> and
- * Frank Copeland <fjc@thingy.apana.org.au> */
-UNUSUAL_DEV( 0x04a5, 0x3010, 0x0100, 0x0100,
- "Tekom Technologies, Inc",
- "300_CAMERA",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_IGNORE_RESIDUE ),
-
#ifdef CONFIG_USB_STORAGE_CYPRESS_ATACB
/* CY7C68300 : support atacb */
UNUSUAL_DEV( 0x04b4, 0x6830, 0x0000, 0x9999,
@@ -594,6 +480,12 @@ UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208,
"eUSB SmartMedia / CompactFlash Adapter",
US_SC_SCSI, US_PR_DPCM_USB, usb_stor_sddr09_dpcm_init,
0),
+#else
+UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208,
+ "SCM Microsystems",
+ "eUSB CompactFlash Adapter",
+ US_SC_SCSI, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN),
#endif
/* Reported by Markus Demleitner <msdemlei@cl.uni-heidelberg.de> */
@@ -685,6 +577,13 @@ UNUSUAL_DEV( 0x0525, 0xa140, 0x0100, 0x0100,
US_SC_8070, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
+/* Added by Alan Stern <stern@rowland.harvard.edu> */
+COMPLIANT_DEV(0x0525, 0xa4a5, 0x0000, 0x9999,
+ "Linux",
+ "File-backed Storage Gadget",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_CAPACITY_OK ),
+
/* Yakumo Mega Image 37
* Submitted by Stephan Fuhrmann <atomenergie@t-online.de> */
UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100,
@@ -807,15 +706,15 @@ UNUSUAL_DEV( 0x054c, 0x006d, 0x0000, 0x9999,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
-/* Submitted by Mike Alborn <malborn@deandra.homeip.net> */
-UNUSUAL_DEV( 0x054c, 0x016a, 0x0000, 0x9999,
+/* Submitted by Frank Engel <frankie@cse.unsw.edu.au> */
+UNUSUAL_DEV( 0x054c, 0x0099, 0x0000, 0x9999,
"Sony",
"PEG Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
-
-/* Submitted by Frank Engel <frankie@cse.unsw.edu.au> */
-UNUSUAL_DEV( 0x054c, 0x0099, 0x0000, 0x9999,
+
+/* Submitted by Mike Alborn <malborn@deandra.homeip.net> */
+UNUSUAL_DEV( 0x054c, 0x016a, 0x0000, 0x9999,
"Sony",
"PEG Mass Storage",
US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -966,6 +865,18 @@ UNUSUAL_DEV( 0x05ac, 0x120a, 0x0000, 0x9999,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
+/* Reported by Dan Williams <dcbw@redhat.com>
+ * Option N.V. mobile broadband modems
+ * Ignore driver CD mode and force into modem mode by default.
+ */
+
+/* Globetrotter HSDPA; mass storage shows up as Qualcomm for vendor */
+UNUSUAL_DEV( 0x05c6, 0x1000, 0x0000, 0x9999,
+ "Option N.V.",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, option_ms_init,
+ 0),
+
#ifdef CONFIG_USB_STORAGE_JUMPSHOT
UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001,
"Lexar",
@@ -1004,6 +915,13 @@ UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ),
+/* Reported by Ben Efros <ben@pc-doctor.com> */
+UNUSUAL_DEV( 0x05e3, 0x0723, 0x9451, 0x9451,
+ "Genesys Logic",
+ "USB to SATA",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_SANE_SENSE ),
+
/* Reported by Hanno Boeck <hanno@gmx.de>
* Taken from the Lycoris Kernel */
UNUSUAL_DEV( 0x0636, 0x0003, 0x0000, 0x9999,
@@ -1040,7 +958,7 @@ UNUSUAL_DEV( 0x067b, 0x2507, 0x0100, 0x0100,
US_FL_FIX_CAPACITY | US_FL_GO_SLOW ),
/* Reported by Alex Butcher <alex.butcher@assursys.co.uk> */
-UNUSUAL_DEV( 0x067b, 0x3507, 0x0001, 0x0001,
+UNUSUAL_DEV( 0x067b, 0x3507, 0x0001, 0x0101,
"Prolific Technology Inc.",
"ATAPI-6 Bridge Controller",
US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -1161,11 +1079,17 @@ UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
-#ifdef CONFIG_USB_STORAGE_DPCM
+#ifdef CONFIG_USB_STORAGE_SDDR09
UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100,
"Microtech",
"CameraMate (DPCM_USB)",
US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ),
+#else
+UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100,
+ "Microtech",
+ "CameraMate",
+ US_SC_SCSI, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN ),
#endif
#ifdef CONFIG_USB_STORAGE_ALAUDA
@@ -1320,6 +1244,13 @@ UNUSUAL_DEV( 0x0840, 0x0082, 0x0001, 0x0001,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY),
+/* Reported and patched by Nguyen Anh Quynh <aquynh@gmail.com> */
+UNUSUAL_DEV( 0x0840, 0x0084, 0x0001, 0x0001,
+ "Argosy",
+ "Storage",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
/* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.
* Flag will support Bulk devices which use a standards-violating 32-byte
* Command Block Wrapper. Here, the "DC2MEGA" cameras (several brands) with
@@ -1343,17 +1274,6 @@ UNUSUAL_DEV( 0x0851, 0x1543, 0x0200, 0x0200,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_NOT_LOCKABLE),
-/* Andrew Lunn <andrew@lunn.ch>
- * PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL
- * on LUN 4.
- * Note: Vend:Prod clash with "Ltd Maxell WS30 Slim Digital Camera"
-*/
-UNUSUAL_DEV( 0x0851, 0x1543, 0x0200, 0x0200,
- "PanDigital",
- "Photo Frame",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_NOT_LOCKABLE),
-
/* Submitted by Jan De Luyck <lkml@kcore.org> */
UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000,
"CITIZEN",
@@ -1425,6 +1345,13 @@ UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
+/* Reported by Jaak Ristioja <Ristioja@gmail.com> */
+UNUSUAL_DEV( 0x0a17, 0x006e, 0x0100, 0x0100,
+ "Pentax",
+ "K10D",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
/* These are virtual windows driver CDs, which the zd1211rw driver
* automatically converts into WLAN devices. */
UNUSUAL_DEV( 0x0ace, 0x2011, 0x0101, 0x0101,
@@ -1439,6 +1366,18 @@ UNUSUAL_DEV( 0x0ace, 0x20ff, 0x0101, 0x0101,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_DEVICE ),
+/* Reported by Dan Williams <dcbw@redhat.com>
+ * Option N.V. mobile broadband modems
+ * Ignore driver CD mode and force into modem mode by default.
+ */
+
+/* iCON 225 */
+UNUSUAL_DEV( 0x0af0, 0x6971, 0x0000, 0x9999,
+ "Option N.V.",
+ "Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, option_ms_init,
+ 0),
+
/* Reported by F. Aben <f.aben@option.com>
* This device (wrongly) has a vendor-specific device descriptor.
* The entry is needed so usb-storage can bind to it's mass-storage
@@ -1449,6 +1388,13 @@ UNUSUAL_DEV( 0x0af0, 0x7401, 0x0000, 0x0000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
0 ),
+/* Reported by Ben Efros <ben@pc-doctor.com> */
+UNUSUAL_DEV( 0x0bc2, 0x3010, 0x0000, 0x0000,
+ "Seagate",
+ "FreeAgent Pro",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_SANE_SENSE ),
+
#ifdef CONFIG_USB_STORAGE_ISD200
UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110,
"ATI",
@@ -1472,6 +1418,22 @@ UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
US_FL_SINGLE_LUN ),
#endif
+UNUSUAL_DEV( 0x0d49, 0x7310, 0x0000, 0x9999,
+ "Maxtor",
+ "USB to SATA",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_SANE_SENSE),
+
+/*
+ * Pete Zaitcev <zaitcev@yahoo.com>, bz#164688.
+ * The device blatantly ignores LUN and returns 1 in GetMaxLUN.
+ */
+UNUSUAL_DEV( 0x0c45, 0x1060, 0x0100, 0x0100,
+ "Unknown",
+ "Unknown",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_SINGLE_LUN ),
+
/* Submitted by: Nick Sillik <n.sillik@temple.edu>
* Needed for OneTouch extension to usb-storage
*
@@ -1489,16 +1451,6 @@ UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
0),
#endif
-/*
- * Pete Zaitcev <zaitcev@yahoo.com>, bz#164688.
- * The device blatantly ignores LUN and returns 1 in GetMaxLUN.
- */
-UNUSUAL_DEV( 0x0c45, 0x1060, 0x0100, 0x0100,
- "Unknown",
- "Unknown",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_SINGLE_LUN ),
-
/* Submitted by Joris Struyve <joris@struyve.be> */
UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff,
"Medion",
@@ -1516,6 +1468,13 @@ UNUSUAL_DEV( 0x0d96, 0x5200, 0x0001, 0x0200,
"JD 5200 z3",
US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
+/* Reported by Jason Johnston <killean@shaw.ca> */
+UNUSUAL_DEV( 0x0dc4, 0x0073, 0x0000, 0x0000,
+ "Macpower Technology Co.LTD.",
+ "USB 2.0 3.5\" DEVICE",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
/* Reported by Lubomir Blaha <tritol@trilogic.cz>
* I _REALLY_ don't know what 3rd, 4th number and all defines mean, but this
* works for me. Can anybody correct these values? (I able to test corrected
@@ -1638,13 +1597,6 @@ UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
-/* Reported by Ricardo Barberis <ricardo@dattatec.com> */
-UNUSUAL_DEV( 0x0fce, 0xe092, 0x0000, 0x0000,
- "Sony Ericsson",
- "P1i",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_IGNORE_RESIDUE ),
-
/* Reported by Emmanuel Vasilakis <evas@forthnet.gr> */
UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000,
"Sony Ericsson",
@@ -1652,6 +1604,13 @@ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+/* Reported by Ricardo Barberis <ricardo@dattatec.com> */
+UNUSUAL_DEV( 0x0fce, 0xe092, 0x0000, 0x0000,
+ "Sony Ericsson",
+ "P1i",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
/* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
* Tested on hardware version 1.10.
* Entry is needed only for the initializer function override.
@@ -1664,6 +1623,12 @@ UNUSUAL_DEV( 0x1019, 0x0c55, 0x0000, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init,
0 ),
+UNUSUAL_DEV( 0x1058, 0x0704, 0x0000, 0x9999,
+ "Western Digital",
+ "External HDD",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_SANE_SENSE),
+
/* Reported by Fabio Venturi <f.venturi@tdnet.it>
* The device reports a vendor-specific bDeviceClass.
*/
@@ -2053,10 +2018,10 @@ UNUSUAL_DEV( 0x14cd, 0x6600, 0x0201, 0x0201,
* JMicron responds to USN and several other SCSI ioctls with a
* residue that causes subsequent I/O requests to fail. */
UNUSUAL_DEV( 0x152d, 0x2329, 0x0100, 0x0100,
- "JMicron",
- "USB to ATA/ATAPI Bridge",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_IGNORE_RESIDUE ),
+ "JMicron",
+ "USB to ATA/ATAPI Bridge",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ),
/* Reported by Robert Schedel <r.schedel@yahoo.de>
* Note: this is a 'super top' device like the above 14cd/6600 device */
@@ -2086,27 +2051,6 @@ UNUSUAL_DEV( 0x22b8, 0x3010, 0x0001, 0x0001,
US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
/*
- * Patch by Pete Zaitcev <zaitcev@redhat.com>
- * Report by Mark Patton. Red Hat bz#208928.
- * Added support for rev 0x0002 (Motorola ROKR W5)
- * by Javier Smaldone <javier@smaldone.com.ar>
- */
-UNUSUAL_DEV( 0x22b8, 0x4810, 0x0001, 0x0002,
- "Motorola",
- "RAZR V3i/ROKR W5",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
-
-/*
- * Patch by Jost Diederichs <jost@qdusa.com>
- */
-UNUSUAL_DEV(0x22b8, 0x6410, 0x0001, 0x9999,
- "Motorola Inc.",
- "Motorola Phone (RAZRV3xx)",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_CAPACITY),
-
-/*
* Patch by Constantin Baranov <const@tltsu.ru>
* Report by Andreas Koenecke.
* Motorola ROKR Z6.
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 27016fd2cad1..4becf495ca2d 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -75,9 +75,6 @@
#ifdef CONFIG_USB_STORAGE_SDDR55
#include "sddr55.h"
#endif
-#ifdef CONFIG_USB_STORAGE_DPCM
-#include "dpcm.h"
-#endif
#ifdef CONFIG_USB_STORAGE_FREECOM
#include "freecom.h"
#endif
@@ -103,6 +100,7 @@
#include "cypress_atacb.h"
#endif
#include "sierra_ms.h"
+#include "option_ms.h"
/* Some informational data */
MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@@ -113,6 +111,10 @@ static unsigned int delay_use = 5;
module_param(delay_use, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
+static char quirks[128];
+module_param_string(quirks, quirks, sizeof(quirks), S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
+
/*
* The entries in this table correspond, line for line,
@@ -126,6 +128,8 @@ MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin,bcdDeviceMax), \
.driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
+#define COMPLIANT_DEV UNUSUAL_DEV
+
#define USUAL_DEV(useProto, useTrans, useType) \
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \
.driver_info = (USB_US_TYPE_STOR<<24) }
@@ -134,6 +138,7 @@ static struct usb_device_id storage_usb_ids [] = {
# include "unusual_devs.h"
#undef UNUSUAL_DEV
+#undef COMPLIANT_DEV
#undef USUAL_DEV
/* Terminating entry */
{ }
@@ -164,6 +169,8 @@ MODULE_DEVICE_TABLE (usb, storage_usb_ids);
.initFunction = init_function, \
}
+#define COMPLIANT_DEV UNUSUAL_DEV
+
#define USUAL_DEV(use_protocol, use_transport, use_type) \
{ \
.useProtocol = use_protocol, \
@@ -173,6 +180,7 @@ MODULE_DEVICE_TABLE (usb, storage_usb_ids);
static struct us_unusual_dev us_unusual_dev_list[] = {
# include "unusual_devs.h"
# undef UNUSUAL_DEV
+# undef COMPLIANT_DEV
# undef USUAL_DEV
/* Terminating entry */
@@ -464,13 +472,83 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf)
US_DEBUGP("I/O buffer allocation failed\n");
return -ENOMEM;
}
+ return 0;
+}
- us->sensebuf = kmalloc(US_SENSE_SIZE, GFP_KERNEL);
- if (!us->sensebuf) {
- US_DEBUGP("Sense buffer allocation failed\n");
- return -ENOMEM;
+/* Works only for digits and letters, but small and fast */
+#define TOLOWER(x) ((x) | 0x20)
+
+/* Adjust device flags based on the "quirks=" module parameter */
+static void adjust_quirks(struct us_data *us)
+{
+ char *p;
+ u16 vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor);
+ u16 pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct);
+ unsigned f = 0;
+ unsigned int mask = (US_FL_SANE_SENSE | US_FL_FIX_CAPACITY |
+ US_FL_CAPACITY_HEURISTICS | US_FL_IGNORE_DEVICE |
+ US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 |
+ US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE |
+ US_FL_SINGLE_LUN | US_FL_NO_WP_DETECT);
+
+ p = quirks;
+ while (*p) {
+ /* Each entry consists of VID:PID:flags */
+ if (vid == simple_strtoul(p, &p, 16) &&
+ *p == ':' &&
+ pid == simple_strtoul(p+1, &p, 16) &&
+ *p == ':')
+ break;
+
+ /* Move forward to the next entry */
+ while (*p) {
+ if (*p++ == ',')
+ break;
+ }
}
- return 0;
+ if (!*p) /* No match */
+ return;
+
+ /* Collect the flags */
+ while (*++p && *p != ',') {
+ switch (TOLOWER(*p)) {
+ case 'a':
+ f |= US_FL_SANE_SENSE;
+ break;
+ case 'c':
+ f |= US_FL_FIX_CAPACITY;
+ break;
+ case 'h':
+ f |= US_FL_CAPACITY_HEURISTICS;
+ break;
+ case 'i':
+ f |= US_FL_IGNORE_DEVICE;
+ break;
+ case 'l':
+ f |= US_FL_NOT_LOCKABLE;
+ break;
+ case 'm':
+ f |= US_FL_MAX_SECTORS_64;
+ break;
+ case 'o':
+ f |= US_FL_CAPACITY_OK;
+ break;
+ case 'r':
+ f |= US_FL_IGNORE_RESIDUE;
+ break;
+ case 's':
+ f |= US_FL_SINGLE_LUN;
+ break;
+ case 'w':
+ f |= US_FL_NO_WP_DETECT;
+ break;
+ /* Ignore unrecognized flag characters */
+ }
+ }
+ us->fflags = (us->fflags & ~mask) | f;
+ dev_info(&us->pusb_intf->dev, "Quirks match for "
+ "vid %04x pid %04x: %x\n",
+ vid, pid, f);
}
/* Find an unusual_dev descriptor (always succeeds in the current code) */
@@ -497,6 +575,7 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id)
idesc->bInterfaceProtocol :
unusual_dev->useTransport;
us->fflags = USB_US_ORIG_FLAGS(id->driver_info);
+ adjust_quirks(us);
if (us->fflags & US_FL_IGNORE_DEVICE) {
printk(KERN_INFO USB_STORAGE "device ignored\n");
@@ -562,7 +641,7 @@ static int get_transport(struct us_data *us)
case US_PR_CBI:
us->transport_name = "Control/Bulk/Interrupt";
- us->transport = usb_stor_CBI_transport;
+ us->transport = usb_stor_CB_transport;
us->transport_reset = usb_stor_CB_reset;
us->max_lun = 7;
break;
@@ -675,19 +754,19 @@ static int get_protocol(struct us_data *us)
case US_SC_8020:
us->protocol_name = "8020i";
- us->proto_handler = usb_stor_ATAPI_command;
+ us->proto_handler = usb_stor_pad12_command;
us->max_lun = 0;
break;
case US_SC_QIC:
us->protocol_name = "QIC-157";
- us->proto_handler = usb_stor_qic157_command;
+ us->proto_handler = usb_stor_pad12_command;
us->max_lun = 0;
break;
case US_SC_8070:
us->protocol_name = "8070i";
- us->proto_handler = usb_stor_ATAPI_command;
+ us->proto_handler = usb_stor_pad12_command;
us->max_lun = 0;
break;
@@ -840,8 +919,6 @@ static void dissociate_dev(struct us_data *us)
{
US_DEBUGP("-- %s\n", __func__);
- kfree(us->sensebuf);
-
/* Free the device-related DMA-mapped buffers */
if (us->cr)
usb_buffer_free(us->pusb_dev, sizeof(*us->cr), us->cr,
@@ -1064,6 +1141,7 @@ static struct usb_driver usb_storage_driver = {
static int __init usb_stor_init(void)
{
int retval;
+
printk(KERN_INFO "Initializing USB Mass Storage driver...\n");
/* register the driver, return usb_register return code if error */
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index a4ad73bd832d..65e674e4be99 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -138,7 +138,6 @@ struct us_data {
struct usb_ctrlrequest *cr; /* control requests */
struct usb_sg_request current_sg; /* scatter-gather req. */
unsigned char *iobuf; /* I/O buffer */
- unsigned char *sensebuf; /* sense data buffer */
dma_addr_t cr_dma; /* buffer DMA addresses */
dma_addr_t iobuf_dma;
struct task_struct *ctl_thread; /* the control thread */
@@ -155,6 +154,10 @@ struct us_data {
#ifdef CONFIG_PM
pm_hook suspend_resume_hook;
#endif
+
+ /* hacks for READ CAPACITY bug handling */
+ int use_last_sector_hacks;
+ int last_sector_retries;
};
/* Convert between us_data and the corresponding Scsi_Host */
diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c
index 407a9fcc89cc..9fe4246cecb9 100644
--- a/drivers/usb/wusbcore/rh.c
+++ b/drivers/usb/wusbcore/rh.c
@@ -329,7 +329,7 @@ static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature,
static int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx,
u32 *_buf, u16 wLength)
{
- u16 *buf = (u16 *) _buf;
+ __le16 *buf = (__le16 *)_buf;
if (port_idx > wusbhc->ports_max)
return -EINVAL;
diff --git a/drivers/uwb/i1480/dfu/usb.c b/drivers/uwb/i1480/dfu/usb.c
index 686795e97195..c7080d497311 100644
--- a/drivers/uwb/i1480/dfu/usb.c
+++ b/drivers/uwb/i1480/dfu/usb.c
@@ -387,7 +387,7 @@ int i1480_usb_probe(struct usb_interface *iface, const struct usb_device_id *id)
goto error_create;
}
- /* setup the fops and upload the firmare */
+ /* setup the fops and upload the firmware */
i1480->pre_fw_name = "i1480-pre-phy-0.0.bin";
i1480->mac_fw_name = "i1480-usb-0.0.bin";
i1480->mac_fw_name_deprecate = "ptc-0.0.bin";
diff --git a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h
index 5f1b2951bb83..3421d3339d7d 100644
--- a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h
+++ b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h
@@ -221,7 +221,6 @@ struct i1480u {
struct net_device *net_dev;
spinlock_t lock;
- struct net_device_stats stats;
/* RX context handling */
struct sk_buff *rx_skb;
@@ -271,7 +270,6 @@ extern int i1480u_stop(struct net_device *);
extern int i1480u_hard_start_xmit(struct sk_buff *, struct net_device *);
extern void i1480u_tx_timeout(struct net_device *);
extern int i1480u_set_config(struct net_device *, struct ifmap *);
-extern struct net_device_stats *i1480u_get_stats(struct net_device *);
extern int i1480u_change_mtu(struct net_device *, int);
extern void i1480u_uwb_notifs_cb(void *, struct uwb_dev *, enum uwb_notifs);
diff --git a/drivers/uwb/i1480/i1480u-wlp/lc.c b/drivers/uwb/i1480/i1480u-wlp/lc.c
index 049c05d4cc6a..f272dfe54d49 100644
--- a/drivers/uwb/i1480/i1480u-wlp/lc.c
+++ b/drivers/uwb/i1480/i1480u-wlp/lc.c
@@ -181,6 +181,15 @@ error:
}
#endif
+static const struct net_device_ops i1480u_netdev_ops = {
+ .ndo_open = i1480u_open,
+ .ndo_stop = i1480u_stop,
+ .ndo_start_xmit = i1480u_hard_start_xmit,
+ .ndo_tx_timeout = i1480u_tx_timeout,
+ .ndo_set_config = i1480u_set_config,
+ .ndo_change_mtu = i1480u_change_mtu,
+};
+
static
int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface)
{
@@ -235,13 +244,7 @@ int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface)
net_dev->features |= NETIF_F_HIGHDMA;
net_dev->watchdog_timeo = 5*HZ; /* FIXME: a better default? */
- net_dev->open = i1480u_open;
- net_dev->stop = i1480u_stop;
- net_dev->hard_start_xmit = i1480u_hard_start_xmit;
- net_dev->tx_timeout = i1480u_tx_timeout;
- net_dev->get_stats = i1480u_get_stats;
- net_dev->set_config = i1480u_set_config;
- net_dev->change_mtu = i1480u_change_mtu;
+ net_dev->netdev_ops = &i1480u_netdev_ops;
#ifdef i1480u_FLOW_CONTROL
/* Notification endpoint setup (submitted when we open the device) */
diff --git a/drivers/uwb/i1480/i1480u-wlp/netdev.c b/drivers/uwb/i1480/i1480u-wlp/netdev.c
index e3873ffb942c..73055530e60f 100644
--- a/drivers/uwb/i1480/i1480u-wlp/netdev.c
+++ b/drivers/uwb/i1480/i1480u-wlp/netdev.c
@@ -262,15 +262,6 @@ int i1480u_stop(struct net_device *net_dev)
return 0;
}
-
-/** Report statistics */
-struct net_device_stats *i1480u_get_stats(struct net_device *net_dev)
-{
- struct i1480u *i1480u = netdev_priv(net_dev);
- return &i1480u->stats;
-}
-
-
/**
*
* Change the interface config--we probably don't have to do anything.
diff --git a/drivers/uwb/i1480/i1480u-wlp/rx.c b/drivers/uwb/i1480/i1480u-wlp/rx.c
index 34f4cf9a7d34..25a2758beb61 100644
--- a/drivers/uwb/i1480/i1480u-wlp/rx.c
+++ b/drivers/uwb/i1480/i1480u-wlp/rx.c
@@ -167,7 +167,7 @@ do { \
do { \
if (printk_ratelimit()) \
dev_err(&i1480u->usb_iface->dev, msg); \
- i1480u->stats.rx_dropped++; \
+ i1480u->net_dev->stats.rx_dropped++; \
} while (0)
@@ -193,10 +193,8 @@ void i1480u_skb_deliver(struct i1480u *i1480u)
if (!should_parse)
goto out;
i1480u->rx_skb->protocol = eth_type_trans(i1480u->rx_skb, net_dev);
- i1480u->stats.rx_packets++;
- i1480u->stats.rx_bytes += i1480u->rx_untd_pkt_size;
- net_dev->last_rx = jiffies;
- /* FIXME: flow control: check netif_rx() retval */
+ net_dev->stats.rx_packets++;
+ net_dev->stats.rx_bytes += i1480u->rx_untd_pkt_size;
netif_rx(i1480u->rx_skb); /* deliver */
out:
diff --git a/drivers/uwb/i1480/i1480u-wlp/tx.c b/drivers/uwb/i1480/i1480u-wlp/tx.c
index 39032cc3503e..26bacc009c65 100644
--- a/drivers/uwb/i1480/i1480u-wlp/tx.c
+++ b/drivers/uwb/i1480/i1480u-wlp/tx.c
@@ -117,8 +117,8 @@ void i1480u_tx_cb(struct urb *urb)
switch (urb->status) {
case 0:
spin_lock_irqsave(&i1480u->lock, flags);
- i1480u->stats.tx_packets++;
- i1480u->stats.tx_bytes += urb->actual_length;
+ net_dev->stats.tx_packets++;
+ net_dev->stats.tx_bytes += urb->actual_length;
spin_unlock_irqrestore(&i1480u->lock, flags);
break;
case -ECONNRESET: /* Not an error, but a controlled situation; */
@@ -530,7 +530,7 @@ int i1480u_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
return NETDEV_TX_OK;
error:
dev_kfree_skb_any(skb);
- i1480u->stats.tx_dropped++;
+ net_dev->stats.tx_dropped++;
out:
return NETDEV_TX_OK;
}
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index e39e33e797da..be2b657546ef 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -28,7 +28,7 @@ obj-$(CONFIG_FB_DDC) += fb_ddc.o
obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
# Hardware specific drivers go first
-obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o
+obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o
obj-$(CONFIG_FB_ARC) += arcfb.o
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
@@ -72,7 +72,7 @@ obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o
obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o
obj-$(CONFIG_FB_SGIVW) += sgivwfb.o
obj-$(CONFIG_FB_ACORN) += acornfb.o
-obj-$(CONFIG_FB_ATARI) += atafb.o c2p.o atafb_mfb.o \
+obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \
atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o
obj-$(CONFIG_FB_MAC) += macfb.o
obj-$(CONFIG_FB_HECUBA) += hecubafb.o
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 2ac52fd8cc11..4e046fed1380 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -24,6 +24,7 @@
#include <linux/amba/bus.h>
#include <linux/amba/clcd.h>
#include <linux/clk.h>
+#include <linux/hardirq.h>
#include <asm/sizes.h>
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index b8e9a8682f2d..100f23661465 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -2159,9 +2159,9 @@ static void amifb_imageblit(struct fb_info *info, const struct fb_image *image)
src += pitch;
}
} else {
- c2p(info->screen_base, image->data, dx, dy, width, height,
- par->next_line, par->next_plane, image->width,
- info->var.bits_per_pixel);
+ c2p_planar(info->screen_base, image->data, dx, dy, width,
+ height, par->next_line, par->next_plane,
+ image->width, info->var.bits_per_pixel);
}
}
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index 77eb8b34fbfa..8058572a7428 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -122,7 +122,6 @@ static struct atafb_par {
void *screen_base;
int yres_virtual;
u_long next_line;
- u_long next_plane;
#if defined ATAFB_TT || defined ATAFB_STE
union {
struct {
@@ -149,6 +148,7 @@ static struct atafb_par {
short mono;
short ste_mode;
short bpp;
+ u32 pseudo_palette[16];
} falcon;
#endif
/* Nothing needed for external mode */
@@ -614,7 +614,7 @@ static int tt_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par)
fix->xpanstep = 0;
fix->ypanstep = 1;
fix->ywrapstep = 0;
- fix->line_length = 0;
+ fix->line_length = par->next_line;
fix->accel = FB_ACCEL_ATARIBLITT;
return 0;
}
@@ -691,6 +691,7 @@ static int tt_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
return -EINVAL;
par->yres_virtual = yres_virtual;
par->screen_base = screen_base + var->yoffset * linelen;
+ par->next_line = linelen;
return 0;
}
@@ -884,10 +885,6 @@ static int vdl_prescale[4][3] = {
/* Default hsync timing [mon_type] in picoseconds */
static long h_syncs[4] = { 3000000, 4875000, 4000000, 4875000 };
-#ifdef FBCON_HAS_CFB16
-static u16 fbcon_cfb16_cmap[16];
-#endif
-
static inline int hxx_prescale(struct falcon_hw *hw)
{
return hw->ste_mode ? 16
@@ -918,7 +915,7 @@ static int falcon_encode_fix(struct fb_fix_screeninfo *fix,
fix->visual = FB_VISUAL_TRUECOLOR;
fix->xpanstep = 2;
}
- fix->line_length = 0;
+ fix->line_length = par->next_line;
fix->accel = FB_ACCEL_ATARIBLITT;
return 0;
}
@@ -1394,14 +1391,7 @@ set_screen_base:
par->screen_base = screen_base + var->yoffset * linelen;
par->hw.falcon.xoffset = 0;
- // FIXME!!! sort of works, no crash
- //par->next_line = linelen;
- //par->next_plane = yres_virtual * linelen;
par->next_line = linelen;
- par->next_plane = 2;
- // crashes
- //par->next_plane = linelen;
- //par->next_line = yres_virtual * linelen;
return 0;
}
@@ -1735,10 +1725,10 @@ static int falcon_setcolreg(unsigned int regno, unsigned int red,
(((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) |
(((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) |
((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12);
-#ifdef FBCON_HAS_CFB16
- fbcon_cfb16_cmap[regno] = ((red & 0xf800) |
- ((green & 0xfc00) >> 5) |
- ((blue & 0xf800) >> 11));
+#ifdef ATAFB_FALCON
+ ((u32 *)info->pseudo_palette)[regno] = ((red & 0xf800) |
+ ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11));
#endif
}
return 0;
@@ -1852,7 +1842,7 @@ static int stste_encode_fix(struct fb_fix_screeninfo *fix,
fix->ypanstep = 0;
}
fix->ywrapstep = 0;
- fix->line_length = 0;
+ fix->line_length = par->next_line;
fix->accel = FB_ACCEL_ATARIBLITT;
return 0;
}
@@ -1910,6 +1900,7 @@ static int stste_decode_var(struct fb_var_screeninfo *var,
return -EINVAL;
par->yres_virtual = yres_virtual;
par->screen_base = screen_base + var->yoffset * linelen;
+ par->next_line = linelen;
return 0;
}
@@ -2169,7 +2160,7 @@ static int ext_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par)
fix->xpanstep = 0;
fix->ypanstep = 0;
fix->ywrapstep = 0;
- fix->line_length = 0;
+ fix->line_length = par->next_line;
return 0;
}
@@ -2184,6 +2175,8 @@ static int ext_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
var->xoffset > 0 ||
var->yoffset > 0)
return -EINVAL;
+
+ par->next_line = external_xres_virtual * external_depth / 8;
return 0;
}
@@ -2443,42 +2436,6 @@ static void atafb_set_disp(struct fb_info *info)
atafb_get_fix(&info->fix, info);
info->screen_base = (void *)info->fix.smem_start;
-
- switch (info->fix.type) {
- case FB_TYPE_INTERLEAVED_PLANES:
- switch (info->var.bits_per_pixel) {
- case 2:
- // display->dispsw = &fbcon_iplan2p2;
- break;
- case 4:
- // display->dispsw = &fbcon_iplan2p4;
- break;
- case 8:
- // display->dispsw = &fbcon_iplan2p8;
- break;
- }
- break;
- case FB_TYPE_PACKED_PIXELS:
- switch (info->var.bits_per_pixel) {
-#ifdef FBCON_HAS_MFB
- case 1:
- // display->dispsw = &fbcon_mfb;
- break;
-#endif
-#ifdef FBCON_HAS_CFB8
- case 8:
- // display->dispsw = &fbcon_cfb8;
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16:
- // display->dispsw = &fbcon_cfb16;
- // display->dispsw_data = fbcon_cfb16_cmap;
- break;
-#endif
- }
- break;
- }
}
static int atafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
@@ -2549,6 +2506,13 @@ static void atafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
if (!rect->width || !rect->height)
return;
+#ifdef ATAFB_FALCON
+ if (info->var.bits_per_pixel == 16) {
+ cfb_fillrect(info, rect);
+ return;
+ }
+#endif
+
/*
* We could use hardware clipping but on many cards you get around
* hardware clipping by writing to framebuffer directly.
@@ -2583,6 +2547,13 @@ static void atafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
u32 dx, dy, sx, sy, width, height;
int rev_copy = 0;
+#ifdef ATAFB_FALCON
+ if (info->var.bits_per_pixel == 16) {
+ cfb_copyarea(info, area);
+ return;
+ }
+#endif
+
/* clip the destination */
x2 = area->dx + area->width;
y2 = area->dy + area->height;
@@ -2632,6 +2603,13 @@ static void atafb_imageblit(struct fb_info *info, const struct fb_image *image)
const char *src;
u32 dx, dy, width, height, pitch;
+#ifdef ATAFB_FALCON
+ if (info->var.bits_per_pixel == 16) {
+ cfb_imageblit(info, image);
+ return;
+ }
+#endif
+
/*
* We could use hardware clipping but on many cards you get around
* hardware clipping by writing to framebuffer directly like we are
@@ -2676,10 +2654,9 @@ static void atafb_imageblit(struct fb_info *info, const struct fb_image *image)
src += pitch;
}
} else {
- // only used for logo; broken
- c2p(info->screen_base, image->data, dx, dy, width, height,
- par->next_line, par->next_plane, image->width,
- info->var.bits_per_pixel);
+ c2p_iplan2(info->screen_base, image->data, dx, dy, width,
+ height, par->next_line, image->width,
+ info->var.bits_per_pixel);
}
}
@@ -3098,8 +3075,7 @@ int __init atafb_setup(char *options)
int __init atafb_init(void)
{
- int pad;
- int detected_mode;
+ int pad, detected_mode, error;
unsigned int defmode = 0;
unsigned long mem_req;
@@ -3139,8 +3115,12 @@ int __init atafb_init(void)
printk("atafb_init: initializing Falcon hw\n");
fbhw = &falcon_switch;
atafb_ops.fb_setcolreg = &falcon_setcolreg;
- request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
- "framebuffer/modeswitch", falcon_vbl_switcher);
+ error = request_irq(IRQ_AUTO_4, falcon_vbl_switcher,
+ IRQ_TYPE_PRIO,
+ "framebuffer/modeswitch",
+ falcon_vbl_switcher);
+ if (error)
+ return error;
defmode = DEFMODE_F30;
break;
}
@@ -3225,6 +3205,10 @@ int __init atafb_init(void)
// tries to read from HW which may not be initialized yet
// so set sane var first, then call atafb_set_par
atafb_get_var(&fb_info.var, &fb_info);
+
+#ifdef ATAFB_FALCON
+ fb_info.pseudo_palette = current_par.hw.falcon.pseudo_palette;
+#endif
fb_info.flags = FBINFO_FLAG_DEFAULT;
if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, atafb_modedb,
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 4a4dd9adc328..72facb9eb7db 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -52,11 +52,11 @@ config LCD_ILI9320
then say y to include a power driver for it.
config LCD_TDO24M
- tristate "Toppoly TDO24M LCD Panels support"
+ tristate "Toppoly TDO24M and TDO35S LCD Panels support"
depends on LCD_CLASS_DEVICE && SPI_MASTER
default n
help
- If you have a Toppoly TDO24M series LCD panel, say y here to
+ If you have a Toppoly TDO24M/TDO35S series LCD panel, say y here to
include the support for it.
config LCD_VGG2432A4
@@ -123,17 +123,14 @@ config BACKLIGHT_ATMEL_PWM
To compile this driver as a module, choose M here: the module will be
called atmel-pwm-bl.
-config BACKLIGHT_CORGI
- tristate "Generic (aka Sharp Corgi) Backlight Driver (DEPRECATED)"
+config BACKLIGHT_GENERIC
+ tristate "Generic (aka Sharp Corgi) Backlight Driver"
depends on BACKLIGHT_CLASS_DEVICE
- default n
+ default y
help
Say y to enable the generic platform backlight driver previously
known as the Corgi backlight driver. If you have a Sharp Zaurus
- SL-C7xx, SL-Cxx00 or SL-6000x say y. Most users can say n.
-
- Note: this driver is marked as deprecated, try enable SPI and
- use the new corgi_lcd driver with integrated backlight control
+ SL-C7xx, SL-Cxx00 or SL-6000x say y.
config BACKLIGHT_LOCOMO
tristate "Sharp LOCOMO LCD/Backlight Driver"
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 103427de6703..363b3cb2f01b 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o
-obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o
+obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o
obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 0664fc032235..157057c79ca3 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -40,6 +40,10 @@ static int fb_notifier_callback(struct notifier_block *self,
if (!bd->ops->check_fb ||
bd->ops->check_fb(evdata->info)) {
bd->props.fb_blank = *(int *)evdata->data;
+ if (bd->props.fb_blank == FB_BLANK_UNBLANK)
+ bd->props.state &= ~BL_CORE_FBBLANK;
+ else
+ bd->props.state |= BL_CORE_FBBLANK;
backlight_update_status(bd);
}
mutex_unlock(&bd->ops_lock);
@@ -80,20 +84,18 @@ static ssize_t backlight_show_power(struct device *dev,
static ssize_t backlight_store_power(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- int rc = -ENXIO;
- char *endp;
+ int rc;
struct backlight_device *bd = to_backlight_device(dev);
- int power = simple_strtoul(buf, &endp, 0);
- size_t size = endp - buf;
+ unsigned long power;
- if (*endp && isspace(*endp))
- size++;
- if (size != count)
- return -EINVAL;
+ rc = strict_strtoul(buf, 0, &power);
+ if (rc)
+ return rc;
+ rc = -ENXIO;
mutex_lock(&bd->ops_lock);
if (bd->ops) {
- pr_debug("backlight: set power to %d\n", power);
+ pr_debug("backlight: set power to %lu\n", power);
if (bd->props.power != power) {
bd->props.power = power;
backlight_update_status(bd);
@@ -116,28 +118,25 @@ static ssize_t backlight_show_brightness(struct device *dev,
static ssize_t backlight_store_brightness(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- int rc = -ENXIO;
- char *endp;
+ int rc;
struct backlight_device *bd = to_backlight_device(dev);
- int brightness = simple_strtoul(buf, &endp, 0);
- size_t size = endp - buf;
+ unsigned long brightness;
+
+ rc = strict_strtoul(buf, 0, &brightness);
+ if (rc)
+ return rc;
- if (*endp && isspace(*endp))
- size++;
- if (size != count)
- return -EINVAL;
+ rc = -ENXIO;
mutex_lock(&bd->ops_lock);
if (bd->ops) {
if (brightness > bd->props.max_brightness)
rc = -EINVAL;
else {
- pr_debug("backlight: set brightness to %d\n",
+ pr_debug("backlight: set brightness to %lu\n",
brightness);
- if (bd->props.brightness != brightness) {
- bd->props.brightness = brightness;
- backlight_update_status(bd);
- }
+ bd->props.brightness = brightness;
+ backlight_update_status(bd);
rc = count;
}
}
@@ -170,6 +169,34 @@ static ssize_t backlight_show_actual_brightness(struct device *dev,
static struct class *backlight_class;
+static int backlight_suspend(struct device *dev, pm_message_t state)
+{
+ struct backlight_device *bd = to_backlight_device(dev);
+
+ if (bd->ops->options & BL_CORE_SUSPENDRESUME) {
+ mutex_lock(&bd->ops_lock);
+ bd->props.state |= BL_CORE_SUSPENDED;
+ backlight_update_status(bd);
+ mutex_unlock(&bd->ops_lock);
+ }
+
+ return 0;
+}
+
+static int backlight_resume(struct device *dev)
+{
+ struct backlight_device *bd = to_backlight_device(dev);
+
+ if (bd->ops->options & BL_CORE_SUSPENDRESUME) {
+ mutex_lock(&bd->ops_lock);
+ bd->props.state &= ~BL_CORE_SUSPENDED;
+ backlight_update_status(bd);
+ mutex_unlock(&bd->ops_lock);
+ }
+
+ return 0;
+}
+
static void bl_device_release(struct device *dev)
{
struct backlight_device *bd = to_backlight_device(dev);
@@ -286,6 +313,8 @@ static int __init backlight_class_init(void)
}
backlight_class->dev_attrs = bl_device_attributes;
+ backlight_class->suspend = backlight_suspend;
+ backlight_class->resume = backlight_resume;
return 0;
}
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
deleted file mode 100644
index 4d4d037e3ec9..000000000000
--- a/drivers/video/backlight/corgi_bl.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Backlight Driver for Sharp Zaurus Handhelds (various models)
- *
- * Copyright (c) 2004-2006 Richard Purdie
- *
- * Based on Sharp's 2.4 Backlight Driver
- *
- * 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/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/mutex.h>
-#include <linux/fb.h>
-#include <linux/backlight.h>
-
-static int corgibl_intensity;
-static struct backlight_properties corgibl_data;
-static struct backlight_device *corgi_backlight_device;
-static struct generic_bl_info *bl_machinfo;
-
-static unsigned long corgibl_flags;
-#define CORGIBL_SUSPENDED 0x01
-#define CORGIBL_BATTLOW 0x02
-
-static int corgibl_send_intensity(struct backlight_device *bd)
-{
- int intensity = bd->props.brightness;
-
- if (bd->props.power != FB_BLANK_UNBLANK)
- intensity = 0;
- if (bd->props.fb_blank != FB_BLANK_UNBLANK)
- intensity = 0;
- if (corgibl_flags & CORGIBL_SUSPENDED)
- intensity = 0;
- if (corgibl_flags & CORGIBL_BATTLOW)
- intensity &= bl_machinfo->limit_mask;
-
- bl_machinfo->set_bl_intensity(intensity);
-
- corgibl_intensity = intensity;
-
- if (bl_machinfo->kick_battery)
- bl_machinfo->kick_battery();
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int corgibl_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct backlight_device *bd = platform_get_drvdata(pdev);
-
- corgibl_flags |= CORGIBL_SUSPENDED;
- backlight_update_status(bd);
- return 0;
-}
-
-static int corgibl_resume(struct platform_device *pdev)
-{
- struct backlight_device *bd = platform_get_drvdata(pdev);
-
- corgibl_flags &= ~CORGIBL_SUSPENDED;
- backlight_update_status(bd);
- return 0;
-}
-#else
-#define corgibl_suspend NULL
-#define corgibl_resume NULL
-#endif
-
-static int corgibl_get_intensity(struct backlight_device *bd)
-{
- return corgibl_intensity;
-}
-
-/*
- * Called when the battery is low to limit the backlight intensity.
- * If limit==0 clear any limit, otherwise limit the intensity
- */
-void corgibl_limit_intensity(int limit)
-{
- if (limit)
- corgibl_flags |= CORGIBL_BATTLOW;
- else
- corgibl_flags &= ~CORGIBL_BATTLOW;
- backlight_update_status(corgi_backlight_device);
-}
-EXPORT_SYMBOL(corgibl_limit_intensity);
-
-
-static struct backlight_ops corgibl_ops = {
- .get_brightness = corgibl_get_intensity,
- .update_status = corgibl_send_intensity,
-};
-
-static int corgibl_probe(struct platform_device *pdev)
-{
- struct generic_bl_info *machinfo = pdev->dev.platform_data;
- const char *name = "generic-bl";
-
- bl_machinfo = machinfo;
- if (!machinfo->limit_mask)
- machinfo->limit_mask = -1;
-
- if (machinfo->name)
- name = machinfo->name;
-
- corgi_backlight_device = backlight_device_register (name,
- &pdev->dev, NULL, &corgibl_ops);
- if (IS_ERR (corgi_backlight_device))
- return PTR_ERR (corgi_backlight_device);
-
- platform_set_drvdata(pdev, corgi_backlight_device);
-
- corgi_backlight_device->props.max_brightness = machinfo->max_intensity;
- corgi_backlight_device->props.power = FB_BLANK_UNBLANK;
- corgi_backlight_device->props.brightness = machinfo->default_intensity;
- backlight_update_status(corgi_backlight_device);
-
- printk("Corgi Backlight Driver Initialized.\n");
- return 0;
-}
-
-static int corgibl_remove(struct platform_device *pdev)
-{
- struct backlight_device *bd = platform_get_drvdata(pdev);
-
- corgibl_data.power = 0;
- corgibl_data.brightness = 0;
- backlight_update_status(bd);
-
- backlight_device_unregister(bd);
-
- printk("Corgi Backlight Driver Unloaded\n");
- return 0;
-}
-
-static struct platform_driver corgibl_driver = {
- .probe = corgibl_probe,
- .remove = corgibl_remove,
- .suspend = corgibl_suspend,
- .resume = corgibl_resume,
- .driver = {
- .name = "generic-bl",
- },
-};
-
-static int __init corgibl_init(void)
-{
- return platform_driver_register(&corgibl_driver);
-}
-
-static void __exit corgibl_exit(void)
-{
- platform_driver_unregister(&corgibl_driver);
-}
-
-module_init(corgibl_init);
-module_exit(corgibl_exit);
-
-MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
-MODULE_DESCRIPTION("Corgi Backlight Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
index 26add8898605..b9fe62b475c6 100644
--- a/drivers/video/backlight/cr_bllcd.c
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -259,22 +259,18 @@ static int __init cr_backlight_init(void)
{
int ret = platform_driver_register(&cr_backlight_driver);
- if (!ret) {
- crp = platform_device_alloc("cr_backlight", -1);
- if (!crp)
- return -ENOMEM;
+ if (ret)
+ return ret;
- ret = platform_device_add(crp);
-
- if (ret) {
- platform_device_put(crp);
- platform_driver_unregister(&cr_backlight_driver);
- }
+ crp = platform_device_register_simple("cr_backlight", -1, NULL, 0);
+ if (IS_ERR(crp)) {
+ platform_driver_unregister(&cr_backlight_driver);
+ return PTR_ERR(crp);
}
printk("Carillo Ranch Backlight Driver Initialized.\n");
- return ret;
+ return 0;
}
static void __exit cr_backlight_exit(void)
diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c
new file mode 100644
index 000000000000..6d27f62fdcd0
--- /dev/null
+++ b/drivers/video/backlight/generic_bl.c
@@ -0,0 +1,147 @@
+/*
+ * Generic Backlight Driver
+ *
+ * Copyright (c) 2004-2008 Richard Purdie
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+
+static int genericbl_intensity;
+static struct backlight_device *generic_backlight_device;
+static struct generic_bl_info *bl_machinfo;
+
+/* Flag to signal when the battery is low */
+#define GENERICBL_BATTLOW BL_CORE_DRIVER1
+
+static int genericbl_send_intensity(struct backlight_device *bd)
+{
+ int intensity = bd->props.brightness;
+
+ if (bd->props.power != FB_BLANK_UNBLANK)
+ intensity = 0;
+ if (bd->props.state & BL_CORE_FBBLANK)
+ intensity = 0;
+ if (bd->props.state & BL_CORE_SUSPENDED)
+ intensity = 0;
+ if (bd->props.state & GENERICBL_BATTLOW)
+ intensity &= bl_machinfo->limit_mask;
+
+ bl_machinfo->set_bl_intensity(intensity);
+
+ genericbl_intensity = intensity;
+
+ if (bl_machinfo->kick_battery)
+ bl_machinfo->kick_battery();
+
+ return 0;
+}
+
+static int genericbl_get_intensity(struct backlight_device *bd)
+{
+ return genericbl_intensity;
+}
+
+/*
+ * Called when the battery is low to limit the backlight intensity.
+ * If limit==0 clear any limit, otherwise limit the intensity
+ */
+void corgibl_limit_intensity(int limit)
+{
+ struct backlight_device *bd = generic_backlight_device;
+
+ mutex_lock(&bd->ops_lock);
+ if (limit)
+ bd->props.state |= GENERICBL_BATTLOW;
+ else
+ bd->props.state &= ~GENERICBL_BATTLOW;
+ backlight_update_status(generic_backlight_device);
+ mutex_unlock(&bd->ops_lock);
+}
+EXPORT_SYMBOL(corgibl_limit_intensity);
+
+static struct backlight_ops genericbl_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .get_brightness = genericbl_get_intensity,
+ .update_status = genericbl_send_intensity,
+};
+
+static int genericbl_probe(struct platform_device *pdev)
+{
+ struct generic_bl_info *machinfo = pdev->dev.platform_data;
+ const char *name = "generic-bl";
+ struct backlight_device *bd;
+
+ bl_machinfo = machinfo;
+ if (!machinfo->limit_mask)
+ machinfo->limit_mask = -1;
+
+ if (machinfo->name)
+ name = machinfo->name;
+
+ bd = backlight_device_register (name,
+ &pdev->dev, NULL, &genericbl_ops);
+ if (IS_ERR (bd))
+ return PTR_ERR (bd);
+
+ platform_set_drvdata(pdev, bd);
+
+ bd->props.max_brightness = machinfo->max_intensity;
+ bd->props.power = FB_BLANK_UNBLANK;
+ bd->props.brightness = machinfo->default_intensity;
+ backlight_update_status(bd);
+
+ generic_backlight_device = bd;
+
+ printk("Generic Backlight Driver Initialized.\n");
+ return 0;
+}
+
+static int genericbl_remove(struct platform_device *pdev)
+{
+ struct backlight_device *bd = platform_get_drvdata(pdev);
+
+ bd->props.power = 0;
+ bd->props.brightness = 0;
+ backlight_update_status(bd);
+
+ backlight_device_unregister(bd);
+
+ printk("Generic Backlight Driver Unloaded\n");
+ return 0;
+}
+
+static struct platform_driver genericbl_driver = {
+ .probe = genericbl_probe,
+ .remove = genericbl_remove,
+ .driver = {
+ .name = "generic-bl",
+ },
+};
+
+static int __init genericbl_init(void)
+{
+ return platform_driver_register(&genericbl_driver);
+}
+
+static void __exit genericbl_exit(void)
+{
+ platform_driver_unregister(&genericbl_driver);
+}
+
+module_init(genericbl_init);
+module_exit(genericbl_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("Generic Backlight Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index d4cfed0b26d5..5be55a20d8c7 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -151,19 +151,15 @@ static int __init hp680bl_init(void)
int ret;
ret = platform_driver_register(&hp680bl_driver);
- if (!ret) {
- hp680bl_device = platform_device_alloc("hp680-bl", -1);
- if (!hp680bl_device)
- return -ENOMEM;
-
- ret = platform_device_add(hp680bl_device);
-
- if (ret) {
- platform_device_put(hp680bl_device);
- platform_driver_unregister(&hp680bl_driver);
- }
+ if (ret)
+ return ret;
+ hp680bl_device = platform_device_register_simple("hp680-bl", -1,
+ NULL, 0);
+ if (IS_ERR(hp680bl_device)) {
+ platform_driver_unregister(&hp680bl_driver);
+ return PTR_ERR(hp680bl_device);
}
- return ret;
+ return 0;
}
static void __exit hp680bl_exit(void)
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c
index 06964af761c6..65864c500455 100644
--- a/drivers/video/backlight/mbp_nvidia_bl.c
+++ b/drivers/video/backlight/mbp_nvidia_bl.c
@@ -70,6 +70,7 @@ static int mbp_get_intensity(struct backlight_device *bd)
}
static struct backlight_ops mbp_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
.get_brightness = mbp_get_intensity,
.update_status = mbp_send_intensity,
};
diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c
index 15fb4d58b5bc..9edaf24fd82d 100644
--- a/drivers/video/backlight/progear_bl.c
+++ b/drivers/video/backlight/progear_bl.c
@@ -119,20 +119,16 @@ static int __init progearbl_init(void)
{
int ret = platform_driver_register(&progearbl_driver);
- if (!ret) {
- progearbl_device = platform_device_alloc("progear-bl", -1);
- if (!progearbl_device)
- return -ENOMEM;
-
- ret = platform_device_add(progearbl_device);
-
- if (ret) {
- platform_device_put(progearbl_device);
- platform_driver_unregister(&progearbl_driver);
- }
+ if (ret)
+ return ret;
+ progearbl_device = platform_device_register_simple("progear-bl", -1,
+ NULL, 0);
+ if (IS_ERR(progearbl_device)) {
+ platform_driver_unregister(&progearbl_driver);
+ return PTR_ERR(progearbl_device);
}
- return ret;
+ return 0;
}
static void __exit progearbl_exit(void)
diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c
index 8427669162ea..1dae7f8f3c6b 100644
--- a/drivers/video/backlight/tdo24m.c
+++ b/drivers/video/backlight/tdo24m.c
@@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/spi/spi.h>
+#include <linux/spi/tdo24m.h>
#include <linux/fb.h>
#include <linux/lcd.h>
@@ -31,6 +32,9 @@ struct tdo24m {
struct spi_transfer xfer;
uint8_t *buf;
+ int (*adj_mode)(struct tdo24m *lcd, int mode);
+ int color_invert;
+
int power;
int mode;
};
@@ -66,7 +70,7 @@ static uint32_t lcd_panel_off[] = {
CMD_NULL,
};
-static uint32_t lcd_vga_pass_through[] = {
+static uint32_t lcd_vga_pass_through_tdo24m[] = {
CMD1(0xB0, 0x16),
CMD1(0xBC, 0x80),
CMD1(0xE1, 0x00),
@@ -75,7 +79,7 @@ static uint32_t lcd_vga_pass_through[] = {
CMD_NULL,
};
-static uint32_t lcd_qvga_pass_through[] = {
+static uint32_t lcd_qvga_pass_through_tdo24m[] = {
CMD1(0xB0, 0x16),
CMD1(0xBC, 0x81),
CMD1(0xE1, 0x00),
@@ -84,7 +88,7 @@ static uint32_t lcd_qvga_pass_through[] = {
CMD_NULL,
};
-static uint32_t lcd_vga_transfer[] = {
+static uint32_t lcd_vga_transfer_tdo24m[] = {
CMD1(0xcf, 0x02), /* Blanking period control (1) */
CMD2(0xd0, 0x08, 0x04), /* Blanking period control (2) */
CMD1(0xd1, 0x01), /* CKV timing control on/off */
@@ -110,6 +114,35 @@ static uint32_t lcd_qvga_transfer[] = {
CMD_NULL,
};
+static uint32_t lcd_vga_pass_through_tdo35s[] = {
+ CMD1(0xB0, 0x16),
+ CMD1(0xBC, 0x80),
+ CMD1(0xE1, 0x00),
+ CMD1(0x3B, 0x00),
+ CMD_NULL,
+};
+
+static uint32_t lcd_qvga_pass_through_tdo35s[] = {
+ CMD1(0xB0, 0x16),
+ CMD1(0xBC, 0x81),
+ CMD1(0xE1, 0x00),
+ CMD1(0x3B, 0x22),
+ CMD_NULL,
+};
+
+static uint32_t lcd_vga_transfer_tdo35s[] = {
+ CMD1(0xcf, 0x02), /* Blanking period control (1) */
+ CMD2(0xd0, 0x08, 0x04), /* Blanking period control (2) */
+ CMD1(0xd1, 0x01), /* CKV timing control on/off */
+ CMD2(0xd2, 0x00, 0x1e), /* CKV 1,2 timing control */
+ CMD2(0xd3, 0x14, 0x28), /* OEV timing control */
+ CMD2(0xd4, 0x28, 0x64), /* ASW timing control (1) */
+ CMD1(0xd5, 0x28), /* ASW timing control (2) */
+ CMD0(0x21), /* Invert for normally black display */
+ CMD0(0x29), /* Display on */
+ CMD_NULL,
+};
+
static uint32_t lcd_panel_config[] = {
CMD2(0xb8, 0xff, 0xf9), /* Output control */
CMD0(0x11), /* sleep out */
@@ -148,6 +181,8 @@ static int tdo24m_writes(struct tdo24m *lcd, uint32_t *array)
int nparams, err = 0;
for (; *p != CMD_NULL; p++) {
+ if (!lcd->color_invert && *p == CMD0(0x21))
+ continue;
nparams = (*p >> 30) & 0x3;
@@ -184,12 +219,33 @@ static int tdo24m_adj_mode(struct tdo24m *lcd, int mode)
{
switch (mode) {
case MODE_VGA:
- tdo24m_writes(lcd, lcd_vga_pass_through);
+ tdo24m_writes(lcd, lcd_vga_pass_through_tdo24m);
tdo24m_writes(lcd, lcd_panel_config);
- tdo24m_writes(lcd, lcd_vga_transfer);
+ tdo24m_writes(lcd, lcd_vga_transfer_tdo24m);
break;
case MODE_QVGA:
- tdo24m_writes(lcd, lcd_qvga_pass_through);
+ tdo24m_writes(lcd, lcd_qvga_pass_through_tdo24m);
+ tdo24m_writes(lcd, lcd_panel_config);
+ tdo24m_writes(lcd, lcd_qvga_transfer);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ lcd->mode = mode;
+ return 0;
+}
+
+static int tdo35s_adj_mode(struct tdo24m *lcd, int mode)
+{
+ switch (mode) {
+ case MODE_VGA:
+ tdo24m_writes(lcd, lcd_vga_pass_through_tdo35s);
+ tdo24m_writes(lcd, lcd_panel_config);
+ tdo24m_writes(lcd, lcd_vga_transfer_tdo35s);
+ break;
+ case MODE_QVGA:
+ tdo24m_writes(lcd, lcd_qvga_pass_through_tdo35s);
tdo24m_writes(lcd, lcd_panel_config);
tdo24m_writes(lcd, lcd_qvga_transfer);
break;
@@ -213,7 +269,7 @@ static int tdo24m_power_on(struct tdo24m *lcd)
if (err)
goto out;
- err = tdo24m_adj_mode(lcd, lcd->mode);
+ err = lcd->adj_mode(lcd, lcd->mode);
out:
return err;
}
@@ -262,7 +318,7 @@ static int tdo24m_set_mode(struct lcd_device *ld, struct fb_videomode *m)
if (lcd->mode == mode)
return 0;
- return tdo24m_adj_mode(lcd, mode);
+ return lcd->adj_mode(lcd, mode);
}
static struct lcd_ops tdo24m_ops = {
@@ -276,8 +332,16 @@ static int __devinit tdo24m_probe(struct spi_device *spi)
struct tdo24m *lcd;
struct spi_message *m;
struct spi_transfer *x;
+ struct tdo24m_platform_data *pdata;
+ enum tdo24m_model model;
int err;
+ pdata = spi->dev.platform_data;
+ if (pdata)
+ model = pdata->model;
+ else
+ model = TDO24M;
+
spi->bits_per_word = 8;
spi->mode = SPI_MODE_3;
err = spi_setup(spi);
@@ -306,6 +370,20 @@ static int __devinit tdo24m_probe(struct spi_device *spi)
x->tx_buf = &lcd->buf[0];
spi_message_add_tail(x, m);
+ switch (model) {
+ case TDO24M:
+ lcd->color_invert = 1;
+ lcd->adj_mode = tdo24m_adj_mode;
+ break;
+ case TDO35S:
+ lcd->adj_mode = tdo35s_adj_mode;
+ lcd->color_invert = 0;
+ break;
+ default:
+ dev_err(&spi->dev, "Unsupported model");
+ goto out_free;
+ }
+
lcd->lcd_dev = lcd_device_register("tdo24m", &spi->dev,
lcd, &tdo24m_ops);
if (IS_ERR(lcd->lcd_dev)) {
diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c
index 57a26649f1a5..b7fbc75a62fc 100644
--- a/drivers/video/backlight/tosa_lcd.c
+++ b/drivers/video/backlight/tosa_lcd.c
@@ -39,6 +39,7 @@ struct tosa_lcd_data {
struct i2c_client *i2c;
int lcd_power;
+ bool is_vga;
};
static int tosa_tg_send(struct spi_device *spi, int adrs, uint8_t data)
@@ -81,8 +82,12 @@ static void tosa_lcd_tg_init(struct tosa_lcd_data *data)
static void tosa_lcd_tg_on(struct tosa_lcd_data *data)
{
struct spi_device *spi = data->spi;
- const int value = TG_REG0_COLOR | TG_REG0_UD | TG_REG0_LR;
- tosa_tg_send(spi, TG_PNLCTL, value | TG_REG0_VQV); /* this depends on mode */
+ int value = TG_REG0_COLOR | TG_REG0_UD | TG_REG0_LR;
+
+ if (data->is_vga)
+ value |= TG_REG0_VQV;
+
+ tosa_tg_send(spi, TG_PNLCTL, value);
/* TG LCD pannel power up */
tosa_tg_send(spi, TG_PINICTL,0x4);
@@ -142,9 +147,25 @@ static int tosa_lcd_get_power(struct lcd_device *lcd)
return data->lcd_power;
}
+static int tosa_lcd_set_mode(struct lcd_device *lcd, struct fb_videomode *mode)
+{
+ struct tosa_lcd_data *data = lcd_get_data(lcd);
+
+ if (mode->xres == 320 || mode->yres == 320)
+ data->is_vga = false;
+ else
+ data->is_vga = true;
+
+ if (POWER_IS_ON(data->lcd_power))
+ tosa_lcd_tg_on(data);
+
+ return 0;
+}
+
static struct lcd_ops tosa_lcd_ops = {
.set_power = tosa_lcd_set_power,
.get_power = tosa_lcd_get_power,
+ .set_mode = tosa_lcd_set_mode,
};
static int __devinit tosa_lcd_probe(struct spi_device *spi)
@@ -156,6 +177,8 @@ static int __devinit tosa_lcd_probe(struct spi_device *spi)
if (!data)
return -ENOMEM;
+ data->is_vga = true; /* defaut to VGA mode */
+
/*
* bits_per_word cannot be configured in platform data
*/
diff --git a/drivers/video/backlight/vgg2432a4.c b/drivers/video/backlight/vgg2432a4.c
index 593c7687d54a..8e653b8a6f17 100644
--- a/drivers/video/backlight/vgg2432a4.c
+++ b/drivers/video/backlight/vgg2432a4.c
@@ -137,7 +137,7 @@ static int vgg2432a4_lcd_init(struct ili9320 *lcd,
ili9320_write(lcd, ILI9320_RGB_IF1, cfg->rgb_if1);
ili9320_write(lcd, ILI9320_FRAMEMAKER, 0x0);
- ili9320_write(lcd, ILI9320_RGB_IF2, ILI9320_RGBIF2_DPL);
+ ili9320_write(lcd, ILI9320_RGB_IF2, cfg->rgb_if2);
ret = ili9320_write_regs(lcd, vgg_init1, ARRAY_SIZE(vgg_init1));
if (ret != 0)
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index 7644ed249564..37e60b1d2ed9 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -335,7 +335,20 @@ static int bfin_bf54x_fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
- if (var->bits_per_pixel != LCD_BPP) {
+ switch (var->bits_per_pixel) {
+ case 24:/* TRUECOLOUR, 16m */
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = var->green.length = var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ break;
+ default:
pr_debug("%s: depth not supported: %u BPP\n", __func__,
var->bits_per_pixel);
return -EINVAL;
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c
index a9b3ada05d99..2a423d3a2a8e 100644
--- a/drivers/video/bfin-t350mcqb-fb.c
+++ b/drivers/video/bfin-t350mcqb-fb.c
@@ -254,7 +254,20 @@ static int bfin_t350mcqb_fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
- if (var->bits_per_pixel != LCD_BPP) {
+ switch (var->bits_per_pixel) {
+ case 24:/* TRUECOLOUR, 16m */
+ var->red.offset = 0;
+ var->green.offset = 8;
+ var->blue.offset = 16;
+ var->red.length = var->green.length = var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ break;
+ default:
pr_debug("%s: depth not supported: %u BPP\n", __func__,
var->bits_per_pixel);
return -EINVAL;
diff --git a/drivers/video/c2p.c b/drivers/video/c2p.c
deleted file mode 100644
index 376bc07ff952..000000000000
--- a/drivers/video/c2p.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Fast C2P (Chunky-to-Planar) Conversion
- *
- * Copyright (C) 2003 Geert Uytterhoeven
- *
- * NOTES:
- * - This code was inspired by Scout's C2P tutorial
- * - It assumes to run on a big endian system
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include "c2p.h"
-
-
- /*
- * Basic transpose step
- */
-
-#define _transp(d, i1, i2, shift, mask) \
- do { \
- u32 t = (d[i1] ^ (d[i2] >> shift)) & mask; \
- d[i1] ^= t; \
- d[i2] ^= t << shift; \
- } while (0)
-
-static inline u32 get_mask(int n)
-{
- switch (n) {
- case 1:
- return 0x55555555;
- break;
-
- case 2:
- return 0x33333333;
- break;
-
- case 4:
- return 0x0f0f0f0f;
- break;
-
- case 8:
- return 0x00ff00ff;
- break;
-
- case 16:
- return 0x0000ffff;
- break;
- }
- return 0;
-}
-
-#define transp_nx1(d, n) \
- do { \
- u32 mask = get_mask(n); \
- /* First block */ \
- _transp(d, 0, 1, n, mask); \
- /* Second block */ \
- _transp(d, 2, 3, n, mask); \
- /* Third block */ \
- _transp(d, 4, 5, n, mask); \
- /* Fourth block */ \
- _transp(d, 6, 7, n, mask); \
- } while (0)
-
-#define transp_nx2(d, n) \
- do { \
- u32 mask = get_mask(n); \
- /* First block */ \
- _transp(d, 0, 2, n, mask); \
- _transp(d, 1, 3, n, mask); \
- /* Second block */ \
- _transp(d, 4, 6, n, mask); \
- _transp(d, 5, 7, n, mask); \
- } while (0)
-
-#define transp_nx4(d, n) \
- do { \
- u32 mask = get_mask(n); \
- _transp(d, 0, 4, n, mask); \
- _transp(d, 1, 5, n, mask); \
- _transp(d, 2, 6, n, mask); \
- _transp(d, 3, 7, n, mask); \
- } while (0)
-
-#define transp(d, n, m) transp_nx ## m(d, n)
-
-
- /*
- * Perform a full C2P step on 32 8-bit pixels, stored in 8 32-bit words
- * containing
- * - 32 8-bit chunky pixels on input
- * - permuted planar data on output
- */
-
-static void c2p_8bpp(u32 d[8])
-{
- transp(d, 16, 4);
- transp(d, 8, 2);
- transp(d, 4, 1);
- transp(d, 2, 4);
- transp(d, 1, 2);
-}
-
-
- /*
- * Array containing the permution indices of the planar data after c2p
- */
-
-static const int perm_c2p_8bpp[8] = { 7, 5, 3, 1, 6, 4, 2, 0 };
-
-
- /*
- * Compose two values, using a bitmask as decision value
- * This is equivalent to (a & mask) | (b & ~mask)
- */
-
-static inline unsigned long comp(unsigned long a, unsigned long b,
- unsigned long mask)
-{
- return ((a ^ b) & mask) ^ b;
-}
-
-
- /*
- * Store a full block of planar data after c2p conversion
- */
-
-static inline void store_planar(char *dst, u32 dst_inc, u32 bpp, u32 d[8])
-{
- int i;
-
- for (i = 0; i < bpp; i++, dst += dst_inc)
- *(u32 *)dst = d[perm_c2p_8bpp[i]];
-}
-
-
- /*
- * Store a partial block of planar data after c2p conversion
- */
-
-static inline void store_planar_masked(char *dst, u32 dst_inc, u32 bpp,
- u32 d[8], u32 mask)
-{
- int i;
-
- for (i = 0; i < bpp; i++, dst += dst_inc)
- *(u32 *)dst = comp(d[perm_c2p_8bpp[i]], *(u32 *)dst, mask);
-}
-
-
- /*
- * c2p - Copy 8-bit chunky image data to a planar frame buffer
- * @dst: Starting address of the planar frame buffer
- * @dx: Horizontal destination offset (in pixels)
- * @dy: Vertical destination offset (in pixels)
- * @width: Image width (in pixels)
- * @height: Image height (in pixels)
- * @dst_nextline: Frame buffer offset to the next line (in bytes)
- * @dst_nextplane: Frame buffer offset to the next plane (in bytes)
- * @src_nextline: Image offset to the next line (in bytes)
- * @bpp: Bits per pixel of the planar frame buffer (1-8)
- */
-
-void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height,
- u32 dst_nextline, u32 dst_nextplane, u32 src_nextline, u32 bpp)
-{
- int dst_idx;
- u32 d[8], first, last, w;
- const u8 *c;
- u8 *p;
-
- dst += dy*dst_nextline+(dx & ~31);
- dst_idx = dx % 32;
- first = ~0UL >> dst_idx;
- last = ~(~0UL >> ((dst_idx+width) % 32));
- while (height--) {
- c = src;
- p = dst;
- w = width;
- if (dst_idx+width <= 32) {
- /* Single destination word */
- first &= last;
- memset(d, 0, sizeof(d));
- memcpy((u8 *)d+dst_idx, c, width);
- c += width;
- c2p_8bpp(d);
- store_planar_masked(p, dst_nextplane, bpp, d, first);
- p += 4;
- } else {
- /* Multiple destination words */
- w = width;
- /* Leading bits */
- if (dst_idx) {
- w = 32 - dst_idx;
- memset(d, 0, dst_idx);
- memcpy((u8 *)d+dst_idx, c, w);
- c += w;
- c2p_8bpp(d);
- store_planar_masked(p, dst_nextplane, bpp, d, first);
- p += 4;
- w = width-w;
- }
- /* Main chunk */
- while (w >= 32) {
- memcpy(d, c, 32);
- c += 32;
- c2p_8bpp(d);
- store_planar(p, dst_nextplane, bpp, d);
- p += 4;
- w -= 32;
- }
- /* Trailing bits */
- w %= 32;
- if (w > 0) {
- memcpy(d, c, w);
- memset((u8 *)d+w, 0, 32-w);
- c2p_8bpp(d);
- store_planar_masked(p, dst_nextplane, bpp, d, last);
- }
- }
- src += src_nextline;
- dst += dst_nextline;
- }
-}
-EXPORT_SYMBOL_GPL(c2p);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/c2p.h b/drivers/video/c2p.h
index c77cbf17e043..6c38d40427d8 100644
--- a/drivers/video/c2p.h
+++ b/drivers/video/c2p.h
@@ -1,7 +1,7 @@
/*
* Fast C2P (Chunky-to-Planar) Conversion
*
- * Copyright (C) 2003 Geert Uytterhoeven
+ * Copyright (C) 2003-2008 Geert Uytterhoeven
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
@@ -10,7 +10,10 @@
#include <linux/types.h>
-extern void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height,
- u32 dst_nextline, u32 dst_nextplane, u32 src_nextline,
- u32 bpp);
+extern void c2p_planar(void *dst, const void *src, u32 dx, u32 dy, u32 width,
+ u32 height, u32 dst_nextline, u32 dst_nextplane,
+ u32 src_nextline, u32 bpp);
+extern void c2p_iplan2(void *dst, const void *src, u32 dx, u32 dy, u32 width,
+ u32 height, u32 dst_nextline, u32 src_nextline,
+ u32 bpp);
diff --git a/drivers/video/c2p_core.h b/drivers/video/c2p_core.h
new file mode 100644
index 000000000000..e1035a865fb9
--- /dev/null
+++ b/drivers/video/c2p_core.h
@@ -0,0 +1,153 @@
+/*
+ * Fast C2P (Chunky-to-Planar) Conversion
+ *
+ * Copyright (C) 2003-2008 Geert Uytterhoeven
+ *
+ * NOTES:
+ * - This code was inspired by Scout's C2P tutorial
+ * - It assumes to run on a big endian system
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+
+ /*
+ * Basic transpose step
+ */
+
+static inline void _transp(u32 d[], unsigned int i1, unsigned int i2,
+ unsigned int shift, u32 mask)
+{
+ u32 t = (d[i1] ^ (d[i2] >> shift)) & mask;
+
+ d[i1] ^= t;
+ d[i2] ^= t << shift;
+}
+
+
+extern void c2p_unsupported(void);
+
+static inline u32 get_mask(unsigned int n)
+{
+ switch (n) {
+ case 1:
+ return 0x55555555;
+
+ case 2:
+ return 0x33333333;
+
+ case 4:
+ return 0x0f0f0f0f;
+
+ case 8:
+ return 0x00ff00ff;
+
+ case 16:
+ return 0x0000ffff;
+ }
+
+ c2p_unsupported();
+ return 0;
+}
+
+
+ /*
+ * Transpose operations on 8 32-bit words
+ */
+
+static inline void transp8(u32 d[], unsigned int n, unsigned int m)
+{
+ u32 mask = get_mask(n);
+
+ switch (m) {
+ case 1:
+ /* First n x 1 block */
+ _transp(d, 0, 1, n, mask);
+ /* Second n x 1 block */
+ _transp(d, 2, 3, n, mask);
+ /* Third n x 1 block */
+ _transp(d, 4, 5, n, mask);
+ /* Fourth n x 1 block */
+ _transp(d, 6, 7, n, mask);
+ return;
+
+ case 2:
+ /* First n x 2 block */
+ _transp(d, 0, 2, n, mask);
+ _transp(d, 1, 3, n, mask);
+ /* Second n x 2 block */
+ _transp(d, 4, 6, n, mask);
+ _transp(d, 5, 7, n, mask);
+ return;
+
+ case 4:
+ /* Single n x 4 block */
+ _transp(d, 0, 4, n, mask);
+ _transp(d, 1, 5, n, mask);
+ _transp(d, 2, 6, n, mask);
+ _transp(d, 3, 7, n, mask);
+ return;
+ }
+
+ c2p_unsupported();
+}
+
+
+ /*
+ * Transpose operations on 4 32-bit words
+ */
+
+static inline void transp4(u32 d[], unsigned int n, unsigned int m)
+{
+ u32 mask = get_mask(n);
+
+ switch (m) {
+ case 1:
+ /* First n x 1 block */
+ _transp(d, 0, 1, n, mask);
+ /* Second n x 1 block */
+ _transp(d, 2, 3, n, mask);
+ return;
+
+ case 2:
+ /* Single n x 2 block */
+ _transp(d, 0, 2, n, mask);
+ _transp(d, 1, 3, n, mask);
+ return;
+ }
+
+ c2p_unsupported();
+}
+
+
+ /*
+ * Transpose operations on 4 32-bit words (reverse order)
+ */
+
+static inline void transp4x(u32 d[], unsigned int n, unsigned int m)
+{
+ u32 mask = get_mask(n);
+
+ switch (m) {
+ case 2:
+ /* Single n x 2 block */
+ _transp(d, 2, 0, n, mask);
+ _transp(d, 3, 1, n, mask);
+ return;
+ }
+
+ c2p_unsupported();
+}
+
+
+ /*
+ * Compose two values, using a bitmask as decision value
+ * This is equivalent to (a & mask) | (b & ~mask)
+ */
+
+static inline u32 comp(u32 a, u32 b, u32 mask)
+{
+ return ((a ^ b) & mask) ^ b;
+}
diff --git a/drivers/video/c2p_iplan2.c b/drivers/video/c2p_iplan2.c
new file mode 100644
index 000000000000..19156dc6158c
--- /dev/null
+++ b/drivers/video/c2p_iplan2.c
@@ -0,0 +1,153 @@
+/*
+ * Fast C2P (Chunky-to-Planar) Conversion
+ *
+ * Copyright (C) 2003-2008 Geert Uytterhoeven
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <asm/unaligned.h>
+
+#include "c2p.h"
+#include "c2p_core.h"
+
+
+ /*
+ * Perform a full C2P step on 16 8-bit pixels, stored in 4 32-bit words
+ * containing
+ * - 16 8-bit chunky pixels on input
+ * - permutated planar data (2 planes per 32-bit word) on output
+ */
+
+static void c2p_16x8(u32 d[4])
+{
+ transp4(d, 8, 2);
+ transp4(d, 1, 2);
+ transp4x(d, 16, 2);
+ transp4x(d, 2, 2);
+ transp4(d, 4, 1);
+}
+
+
+ /*
+ * Array containing the permutation indices of the planar data after c2p
+ */
+
+static const int perm_c2p_16x8[4] = { 1, 3, 0, 2 };
+
+
+ /*
+ * Store a full block of iplan2 data after c2p conversion
+ */
+
+static inline void store_iplan2(void *dst, u32 bpp, u32 d[4])
+{
+ int i;
+
+ for (i = 0; i < bpp/2; i++, dst += 4)
+ put_unaligned_be32(d[perm_c2p_16x8[i]], dst);
+}
+
+
+ /*
+ * Store a partial block of iplan2 data after c2p conversion
+ */
+
+static inline void store_iplan2_masked(void *dst, u32 bpp, u32 d[4], u32 mask)
+{
+ int i;
+
+ for (i = 0; i < bpp/2; i++, dst += 4)
+ put_unaligned_be32(comp(d[perm_c2p_16x8[i]],
+ get_unaligned_be32(dst), mask),
+ dst);
+}
+
+
+ /*
+ * c2p_iplan2 - Copy 8-bit chunky image data to an interleaved planar
+ * frame buffer with 2 bytes of interleave
+ * @dst: Starting address of the planar frame buffer
+ * @dx: Horizontal destination offset (in pixels)
+ * @dy: Vertical destination offset (in pixels)
+ * @width: Image width (in pixels)
+ * @height: Image height (in pixels)
+ * @dst_nextline: Frame buffer offset to the next line (in bytes)
+ * @src_nextline: Image offset to the next line (in bytes)
+ * @bpp: Bits per pixel of the planar frame buffer (2, 4, or 8)
+ */
+
+void c2p_iplan2(void *dst, const void *src, u32 dx, u32 dy, u32 width,
+ u32 height, u32 dst_nextline, u32 src_nextline, u32 bpp)
+{
+ union {
+ u8 pixels[16];
+ u32 words[4];
+ } d;
+ u32 dst_idx, first, last, w;
+ const u8 *c;
+ void *p;
+
+ dst += dy*dst_nextline+(dx & ~15)*bpp;
+ dst_idx = dx % 16;
+ first = 0xffffU >> dst_idx;
+ first |= first << 16;
+ last = 0xffffU ^ (0xffffU >> ((dst_idx+width) % 16));
+ last |= last << 16;
+ while (height--) {
+ c = src;
+ p = dst;
+ w = width;
+ if (dst_idx+width <= 16) {
+ /* Single destination word */
+ first &= last;
+ memset(d.pixels, 0, sizeof(d));
+ memcpy(d.pixels+dst_idx, c, width);
+ c += width;
+ c2p_16x8(d.words);
+ store_iplan2_masked(p, bpp, d.words, first);
+ p += bpp*2;
+ } else {
+ /* Multiple destination words */
+ w = width;
+ /* Leading bits */
+ if (dst_idx) {
+ w = 16 - dst_idx;
+ memset(d.pixels, 0, dst_idx);
+ memcpy(d.pixels+dst_idx, c, w);
+ c += w;
+ c2p_16x8(d.words);
+ store_iplan2_masked(p, bpp, d.words, first);
+ p += bpp*2;
+ w = width-w;
+ }
+ /* Main chunk */
+ while (w >= 16) {
+ memcpy(d.pixels, c, 16);
+ c += 16;
+ c2p_16x8(d.words);
+ store_iplan2(p, bpp, d.words);
+ p += bpp*2;
+ w -= 16;
+ }
+ /* Trailing bits */
+ w %= 16;
+ if (w > 0) {
+ memcpy(d.pixels, c, w);
+ memset(d.pixels+w, 0, 16-w);
+ c2p_16x8(d.words);
+ store_iplan2_masked(p, bpp, d.words, last);
+ }
+ }
+ src += src_nextline;
+ dst += dst_nextline;
+ }
+}
+EXPORT_SYMBOL_GPL(c2p_iplan2);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/c2p_planar.c b/drivers/video/c2p_planar.c
new file mode 100644
index 000000000000..ec7ac8526f06
--- /dev/null
+++ b/drivers/video/c2p_planar.c
@@ -0,0 +1,156 @@
+/*
+ * Fast C2P (Chunky-to-Planar) Conversion
+ *
+ * Copyright (C) 2003-2008 Geert Uytterhoeven
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <asm/unaligned.h>
+
+#include "c2p.h"
+#include "c2p_core.h"
+
+
+ /*
+ * Perform a full C2P step on 32 8-bit pixels, stored in 8 32-bit words
+ * containing
+ * - 32 8-bit chunky pixels on input
+ * - permutated planar data (1 plane per 32-bit word) on output
+ */
+
+static void c2p_32x8(u32 d[8])
+{
+ transp8(d, 16, 4);
+ transp8(d, 8, 2);
+ transp8(d, 4, 1);
+ transp8(d, 2, 4);
+ transp8(d, 1, 2);
+}
+
+
+ /*
+ * Array containing the permutation indices of the planar data after c2p
+ */
+
+static const int perm_c2p_32x8[8] = { 7, 5, 3, 1, 6, 4, 2, 0 };
+
+
+ /*
+ * Store a full block of planar data after c2p conversion
+ */
+
+static inline void store_planar(void *dst, u32 dst_inc, u32 bpp, u32 d[8])
+{
+ int i;
+
+ for (i = 0; i < bpp; i++, dst += dst_inc)
+ put_unaligned_be32(d[perm_c2p_32x8[i]], dst);
+}
+
+
+ /*
+ * Store a partial block of planar data after c2p conversion
+ */
+
+static inline void store_planar_masked(void *dst, u32 dst_inc, u32 bpp,
+ u32 d[8], u32 mask)
+{
+ int i;
+
+ for (i = 0; i < bpp; i++, dst += dst_inc)
+ put_unaligned_be32(comp(d[perm_c2p_32x8[i]],
+ get_unaligned_be32(dst), mask),
+ dst);
+}
+
+
+ /*
+ * c2p_planar - Copy 8-bit chunky image data to a planar frame buffer
+ * @dst: Starting address of the planar frame buffer
+ * @dx: Horizontal destination offset (in pixels)
+ * @dy: Vertical destination offset (in pixels)
+ * @width: Image width (in pixels)
+ * @height: Image height (in pixels)
+ * @dst_nextline: Frame buffer offset to the next line (in bytes)
+ * @dst_nextplane: Frame buffer offset to the next plane (in bytes)
+ * @src_nextline: Image offset to the next line (in bytes)
+ * @bpp: Bits per pixel of the planar frame buffer (1-8)
+ */
+
+void c2p_planar(void *dst, const void *src, u32 dx, u32 dy, u32 width,
+ u32 height, u32 dst_nextline, u32 dst_nextplane,
+ u32 src_nextline, u32 bpp)
+{
+ union {
+ u8 pixels[32];
+ u32 words[8];
+ } d;
+ u32 dst_idx, first, last, w;
+ const u8 *c;
+ void *p;
+
+ dst += dy*dst_nextline+(dx & ~31);
+ dst_idx = dx % 32;
+ first = 0xffffffffU >> dst_idx;
+ last = ~(0xffffffffU >> ((dst_idx+width) % 32));
+ while (height--) {
+ c = src;
+ p = dst;
+ w = width;
+ if (dst_idx+width <= 32) {
+ /* Single destination word */
+ first &= last;
+ memset(d.pixels, 0, sizeof(d));
+ memcpy(d.pixels+dst_idx, c, width);
+ c += width;
+ c2p_32x8(d.words);
+ store_planar_masked(p, dst_nextplane, bpp, d.words,
+ first);
+ p += 4;
+ } else {
+ /* Multiple destination words */
+ w = width;
+ /* Leading bits */
+ if (dst_idx) {
+ w = 32 - dst_idx;
+ memset(d.pixels, 0, dst_idx);
+ memcpy(d.pixels+dst_idx, c, w);
+ c += w;
+ c2p_32x8(d.words);
+ store_planar_masked(p, dst_nextplane, bpp,
+ d.words, first);
+ p += 4;
+ w = width-w;
+ }
+ /* Main chunk */
+ while (w >= 32) {
+ memcpy(d.pixels, c, 32);
+ c += 32;
+ c2p_32x8(d.words);
+ store_planar(p, dst_nextplane, bpp, d.words);
+ p += 4;
+ w -= 32;
+ }
+ /* Trailing bits */
+ w %= 32;
+ if (w > 0) {
+ memcpy(d.pixels, c, w);
+ memset(d.pixels+w, 0, 32-w);
+ c2p_32x8(d.words);
+ store_planar_masked(p, dst_nextplane, bpp,
+ d.words, last);
+ }
+ }
+ src += src_nextline;
+ dst += dst_nextline;
+ }
+}
+EXPORT_SYMBOL_GPL(c2p_planar);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 4bcff81b50e0..1657b9608b04 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -78,13 +78,6 @@
#include <asm/fb.h>
#include <asm/irq.h>
#include <asm/system.h>
-#ifdef CONFIG_ATARI
-#include <asm/atariints.h>
-#endif
-#if defined(__mc68000__)
-#include <asm/machdep.h>
-#include <asm/setup.h>
-#endif
#include "fbcon.h"
@@ -155,9 +148,6 @@ static int fbcon_set_origin(struct vc_data *);
#define CURSOR_DRAW_DELAY (1)
-/* # VBL ints between cursor state changes */
-#define ATARI_CURSOR_BLINK_RATE (42)
-
static int vbl_cursor_cnt;
static int fbcon_cursor_noblink;
@@ -403,20 +393,6 @@ static void fb_flashcursor(struct work_struct *work)
release_console_sem();
}
-#ifdef CONFIG_ATARI
-static int cursor_blink_rate;
-static irqreturn_t fb_vbl_handler(int irq, void *dev_id)
-{
- struct fb_info *info = dev_id;
-
- if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) {
- schedule_work(&info->queue);
- vbl_cursor_cnt = cursor_blink_rate;
- }
- return IRQ_HANDLED;
-}
-#endif
-
static void cursor_timer_handler(unsigned long dev_addr)
{
struct fb_info *info = (struct fb_info *) dev_addr;
@@ -1017,15 +993,6 @@ static const char *fbcon_startup(void)
info->var.yres,
info->var.bits_per_pixel);
-#ifdef CONFIG_ATARI
- if (MACH_IS_ATARI) {
- cursor_blink_rate = ATARI_CURSOR_BLINK_RATE;
- (void)request_irq(IRQ_AUTO_4, fb_vbl_handler,
- IRQ_TYPE_PRIO, "framebuffer vbl",
- info);
- }
-#endif /* CONFIG_ATARI */
-
fbcon_add_cursor_timer(info);
fbcon_has_exited = 0;
return display_desc;
@@ -3454,11 +3421,6 @@ static void fbcon_exit(void)
if (fbcon_has_exited)
return;
-#ifdef CONFIG_ATARI
- if (MACH_IS_ATARI)
- free_irq(IRQ_AUTO_4, fb_vbl_handler);
-#endif
-
kfree((void *)softback_buf);
softback_buf = 0UL;
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index e6210725b9ab..d012edda6d11 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -1332,7 +1332,7 @@ static void vgacon_save_screen(struct vc_data *c)
c->vc_y = screen_info.orig_y;
}
- /* We can't copy in more then the size of the video buffer,
+ /* We can't copy in more than the size of the video buffer,
* or we'll be copying in VGA BIOS */
if (!vga_is_gfx)
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 38ac805db97d..87f826e4c958 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -1006,7 +1006,7 @@ static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev)
__func__, status);
return -ENXIO;
}
- dev_dbg(dev, "video:%p ioif:%lx lpar:%lx size:%lx\n",
+ dev_dbg(dev, "video:%p ioif:%lx lpar:%llx size:%lx\n",
ps3fb_videomemory.address, GPU_IOIF, xdr_lpar,
ps3fb_videomemory.size);
@@ -1133,7 +1133,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
__func__, status);
goto err;
}
- dev_dbg(&dev->core, "ddr:lpar:0x%lx\n", ddr_lpar);
+ dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar);
status = lv1_gpu_context_allocate(ps3fb.memory_handle, 0,
&ps3fb.context_handle,
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
index 90616822cd20..96d2f8e4c275 100644
--- a/drivers/w1/masters/Kconfig
+++ b/drivers/w1/masters/Kconfig
@@ -34,6 +34,12 @@ config W1_MASTER_DS2482
This driver can also be built as a module. If so, the module
will be called ds2482.
+config W1_MASTER_MXC
+ tristate "Freescale MXC 1-wire busmaster"
+ depends on W1 && ARCH_MXC
+ help
+ Say Y here to enable MXC 1-wire host
+
config W1_MASTER_DS1WM
tristate "Maxim DS1WM 1-wire busmaster"
depends on W1 && ARM && HAVE_CLK
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile
index bc4714a75f3a..c5a3e96fcbab 100644
--- a/drivers/w1/masters/Makefile
+++ b/drivers/w1/masters/Makefile
@@ -5,6 +5,8 @@
obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o
obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o
obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o
+obj-$(CONFIG_W1_MASTER_MXC) += mxc_w1.o
+
obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o
obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o
obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o
diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c
new file mode 100644
index 000000000000..b9d74d0b353e
--- /dev/null
+++ b/drivers/w1/masters/mxc_w1.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Luotao Fu, kernel@pengutronix.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_log.h"
+
+/* According to the mx27 Datasheet the reset procedure should take up to about
+ * 1350us. We set the timeout to 500*100us = 50ms for sure */
+#define MXC_W1_RESET_TIMEOUT 500
+
+/*
+ * MXC W1 Register offsets
+ */
+#define MXC_W1_CONTROL 0x00
+#define MXC_W1_TIME_DIVIDER 0x02
+#define MXC_W1_RESET 0x04
+#define MXC_W1_COMMAND 0x06
+#define MXC_W1_TXRX 0x08
+#define MXC_W1_INTERRUPT 0x0A
+#define MXC_W1_INTERRUPT_EN 0x0C
+
+struct mxc_w1_device {
+ void __iomem *regs;
+ unsigned int clkdiv;
+ struct clk *clk;
+ struct w1_bus_master bus_master;
+};
+
+/*
+ * this is the low level routine to
+ * reset the device on the One Wire interface
+ * on the hardware
+ */
+static u8 mxc_w1_ds2_reset_bus(void *data)
+{
+ u8 reg_val;
+ unsigned int timeout_cnt = 0;
+ struct mxc_w1_device *dev = data;
+
+ __raw_writeb(0x80, (dev->regs + MXC_W1_CONTROL));
+
+ while (1) {
+ reg_val = __raw_readb(dev->regs + MXC_W1_CONTROL);
+
+ if (((reg_val >> 7) & 0x1) == 0 ||
+ timeout_cnt > MXC_W1_RESET_TIMEOUT)
+ break;
+ else
+ timeout_cnt++;
+
+ udelay(100);
+ }
+ return (reg_val >> 7) & 0x1;
+}
+
+/*
+ * this is the low level routine to read/write a bit on the One Wire
+ * interface on the hardware. It does write 0 if parameter bit is set
+ * to 0, otherwise a write 1/read.
+ */
+static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
+{
+ struct mxc_w1_device *mdev = data;
+ void __iomem *ctrl_addr = mdev->regs + MXC_W1_CONTROL;
+ unsigned int timeout_cnt = 400; /* Takes max. 120us according to
+ * datasheet.
+ */
+
+ __raw_writeb((1 << (5 - bit)), ctrl_addr);
+
+ while (timeout_cnt--) {
+ if (!((__raw_readb(ctrl_addr) >> (5 - bit)) & 0x1))
+ break;
+
+ udelay(1);
+ }
+
+ return ((__raw_readb(ctrl_addr)) >> 3) & 0x1;
+}
+
+static int __init mxc_w1_probe(struct platform_device *pdev)
+{
+ struct mxc_w1_device *mdev;
+ struct resource *res;
+ int err = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ mdev = kzalloc(sizeof(struct mxc_w1_device), GFP_KERNEL);
+ if (!mdev)
+ return -ENOMEM;
+
+ mdev->clk = clk_get(&pdev->dev, "owire_clk");
+ if (!mdev->clk) {
+ err = -ENODEV;
+ goto failed_clk;
+ }
+
+ mdev->clkdiv = (clk_get_rate(mdev->clk) / 1000000) - 1;
+
+ res = request_mem_region(res->start, resource_size(res),
+ "mxc_w1");
+ if (!res) {
+ err = -EBUSY;
+ goto failed_req;
+ }
+
+ mdev->regs = ioremap(res->start, resource_size(res));
+ if (!mdev->regs) {
+ printk(KERN_ERR "Cannot map frame buffer registers\n");
+ goto failed_ioremap;
+ }
+
+ clk_enable(mdev->clk);
+ __raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER);
+
+ mdev->bus_master.data = mdev;
+ mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus;
+ mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit;
+
+ err = w1_add_master_device(&mdev->bus_master);
+
+ if (err)
+ goto failed_add;
+
+ platform_set_drvdata(pdev, mdev);
+ return 0;
+
+failed_add:
+ iounmap(mdev->regs);
+failed_ioremap:
+ release_mem_region(res->start, resource_size(res));
+failed_req:
+ clk_put(mdev->clk);
+failed_clk:
+ kfree(mdev);
+ return err;
+}
+
+/*
+ * disassociate the w1 device from the driver
+ */
+static int mxc_w1_remove(struct platform_device *pdev)
+{
+ struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ w1_remove_master_device(&mdev->bus_master);
+
+ iounmap(mdev->regs);
+ release_mem_region(res->start, resource_size(res));
+ clk_disable(mdev->clk);
+ clk_put(mdev->clk);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver mxc_w1_driver = {
+ .driver = {
+ .name = "mxc_w1",
+ },
+ .probe = mxc_w1_probe,
+ .remove = mxc_w1_remove,
+};
+
+static int __init mxc_w1_init(void)
+{
+ return platform_driver_register(&mxc_w1_driver);
+}
+
+static void mxc_w1_exit(void)
+{
+ platform_driver_unregister(&mxc_w1_driver);
+}
+
+module_init(mxc_w1_init);
+module_exit(mxc_w1_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale Semiconductors Inc");
+MODULE_DESCRIPTION("Driver for One-Wire on MXC");
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h
index 97304bd83ec9..d8a9709f3449 100644
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -210,6 +210,7 @@ u8 w1_read_8(struct w1_master *);
int w1_reset_bus(struct w1_master *);
u8 w1_calc_crc8(u8 *, int);
void w1_write_block(struct w1_master *, const u8 *, int);
+void w1_touch_block(struct w1_master *, u8 *, int);
u8 w1_read_block(struct w1_master *, u8 *, int);
int w1_reset_select_slave(struct w1_slave *sl);
void w1_next_pullup(struct w1_master *, int);
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
index 5139c25ca962..442bd8bbd4a5 100644
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -238,7 +238,6 @@ EXPORT_SYMBOL_GPL(w1_read_8);
* @param dev the master device
* @param buf pointer to the data to write
* @param len the number of bytes to write
- * @return the byte read
*/
void w1_write_block(struct w1_master *dev, const u8 *buf, int len)
{
@@ -256,6 +255,31 @@ void w1_write_block(struct w1_master *dev, const u8 *buf, int len)
EXPORT_SYMBOL_GPL(w1_write_block);
/**
+ * Touches a series of bytes.
+ *
+ * @param dev the master device
+ * @param buf pointer to the data to write
+ * @param len the number of bytes to write
+ */
+void w1_touch_block(struct w1_master *dev, u8 *buf, int len)
+{
+ int i, j;
+ u8 tmp;
+
+ for (i = 0; i < len; ++i) {
+ tmp = 0;
+ for (j = 0; j < 8; ++j) {
+ if (j == 7)
+ w1_pre_write(dev);
+ tmp |= w1_touch_bit(dev, (buf[i] >> j) & 0x1) << j;
+ }
+
+ buf[i] = tmp;
+ }
+}
+EXPORT_SYMBOL_GPL(w1_touch_block);
+
+/**
* Reads a series of bytes.
*
* @param dev the master device
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
index 65c5ebd0787e..fdf72851c574 100644
--- a/drivers/w1/w1_netlink.c
+++ b/drivers/w1/w1_netlink.c
@@ -47,21 +47,56 @@ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
cn_netlink_send(m, 0, GFP_KERNEL);
}
-static int w1_process_command_master(struct w1_master *dev, struct cn_msg *msg,
- struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd)
+static void w1_send_slave(struct w1_master *dev, u64 rn)
+{
+ struct cn_msg *msg = dev->priv;
+ struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1);
+ struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1);
+ int avail;
+
+ avail = dev->priv_size - cmd->len;
+
+ if (avail > 8) {
+ u64 *data = (void *)(cmd + 1) + cmd->len;
+
+ *data = rn;
+ cmd->len += 8;
+ hdr->len += 8;
+ msg->len += 8;
+ return;
+ }
+
+ msg->ack++;
+ cn_netlink_send(msg, 0, GFP_KERNEL);
+
+ msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd);
+ hdr->len = sizeof(struct w1_netlink_cmd);
+ cmd->len = 0;
+}
+
+static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg,
+ unsigned int avail)
{
- dev_dbg(&dev->dev, "%s: %s: cmd=%02x, len=%u.\n",
- __func__, dev->name, cmd->cmd, cmd->len);
+ struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1);
+ struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1);
+ int search_type = (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH;
- if (cmd->cmd != W1_CMD_SEARCH && cmd->cmd != W1_CMD_ALARM_SEARCH)
- return -EINVAL;
+ dev->priv = msg;
+ dev->priv_size = avail;
+
+ w1_search_devices(dev, search_type, w1_send_slave);
+
+ msg->ack = 0;
+ cn_netlink_send(msg, 0, GFP_KERNEL);
+
+ dev->priv = NULL;
+ dev->priv_size = 0;
- w1_search_process(dev, (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH);
return 0;
}
-static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg,
- struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd)
+static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr,
+ struct w1_netlink_cmd *cmd)
{
void *data;
struct w1_netlink_msg *h;
@@ -85,7 +120,8 @@ static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg,
memcpy(c, cmd, sizeof(struct w1_netlink_cmd));
cm->ack = msg->seq+1;
- cm->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len;
+ cm->len = sizeof(struct w1_netlink_msg) +
+ sizeof(struct w1_netlink_cmd) + cmd->len;
h->len = sizeof(struct w1_netlink_cmd) + cmd->len;
@@ -98,36 +134,178 @@ static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg,
return err;
}
-static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg,
+static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg,
struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd)
{
int err = 0;
- dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n",
- __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, sl->reg_num.crc,
- cmd->cmd, cmd->len);
+ switch (cmd->cmd) {
+ case W1_CMD_TOUCH:
+ w1_touch_block(dev, cmd->data, cmd->len);
+ w1_send_read_reply(msg, hdr, cmd);
+ break;
+ case W1_CMD_READ:
+ w1_read_block(dev, cmd->data, cmd->len);
+ w1_send_read_reply(msg, hdr, cmd);
+ break;
+ case W1_CMD_WRITE:
+ w1_write_block(dev, cmd->data, cmd->len);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_msg,
+ struct w1_netlink_msg *req_hdr, struct w1_netlink_cmd *req_cmd)
+{
+ int err = -EINVAL;
+ struct cn_msg *msg;
+ struct w1_netlink_msg *hdr;
+ struct w1_netlink_cmd *cmd;
+
+ msg = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->id = req_msg->id;
+ msg->seq = req_msg->seq;
+ msg->ack = 0;
+ msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd);
+
+ hdr = (struct w1_netlink_msg *)(msg + 1);
+ cmd = (struct w1_netlink_cmd *)(hdr + 1);
+
+ hdr->type = W1_MASTER_CMD;
+ hdr->id = req_hdr->id;
+ hdr->len = sizeof(struct w1_netlink_cmd);
+
+ cmd->cmd = req_cmd->cmd;
+ cmd->len = 0;
switch (cmd->cmd) {
- case W1_CMD_READ:
- w1_read_block(sl->master, cmd->data, cmd->len);
- w1_send_read_reply(sl, msg, hdr, cmd);
- break;
- case W1_CMD_WRITE:
- w1_write_block(sl->master, cmd->data, cmd->len);
- break;
- case W1_CMD_SEARCH:
- case W1_CMD_ALARM_SEARCH:
- w1_search_process(sl->master,
- (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH);
- break;
- default:
- err = -1;
- break;
+ case W1_CMD_SEARCH:
+ case W1_CMD_ALARM_SEARCH:
+ err = w1_process_search_command(dev, msg,
+ PAGE_SIZE - msg->len - sizeof(struct cn_msg));
+ break;
+ case W1_CMD_READ:
+ case W1_CMD_WRITE:
+ case W1_CMD_TOUCH:
+ err = w1_process_command_io(dev, req_msg, req_hdr, req_cmd);
+ break;
+ case W1_CMD_RESET:
+ err = w1_reset_bus(dev);
+ break;
+ default:
+ err = -EINVAL;
+ break;
}
+ kfree(msg);
return err;
}
+static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg,
+ struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd)
+{
+ dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n",
+ __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id,
+ sl->reg_num.crc, cmd->cmd, cmd->len);
+
+ return w1_process_command_io(sl->master, msg, hdr, cmd);
+}
+
+static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mcmd)
+{
+ struct w1_master *m;
+ struct cn_msg *cn;
+ struct w1_netlink_msg *w;
+ u32 *id;
+
+ if (mcmd->type != W1_LIST_MASTERS) {
+ printk(KERN_NOTICE "%s: msg: %x.%x, wrong type: %u, len: %u.\n",
+ __func__, msg->id.idx, msg->id.val, mcmd->type, mcmd->len);
+ return -EPROTO;
+ }
+
+ cn = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!cn)
+ return -ENOMEM;
+
+ cn->id.idx = CN_W1_IDX;
+ cn->id.val = CN_W1_VAL;
+
+ cn->seq = msg->seq;
+ cn->ack = 1;
+ cn->len = sizeof(struct w1_netlink_msg);
+ w = (struct w1_netlink_msg *)(cn + 1);
+
+ w->type = W1_LIST_MASTERS;
+ w->status = 0;
+ w->len = 0;
+ id = (u32 *)(w + 1);
+
+ mutex_lock(&w1_mlock);
+ list_for_each_entry(m, &w1_masters, w1_master_entry) {
+ if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) {
+ cn_netlink_send(cn, 0, GFP_KERNEL);
+ cn->ack++;
+ cn->len = sizeof(struct w1_netlink_msg);
+ w->len = 0;
+ id = (u32 *)(w + 1);
+ }
+
+ *id = m->id;
+ w->len += sizeof(*id);
+ cn->len += sizeof(*id);
+ id++;
+ }
+ cn->ack = 0;
+ cn_netlink_send(cn, 0, GFP_KERNEL);
+ mutex_unlock(&w1_mlock);
+
+ kfree(cn);
+ return 0;
+}
+
+static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rmsg,
+ struct w1_netlink_cmd *rcmd, int error)
+{
+ struct cn_msg *cmsg;
+ struct w1_netlink_msg *msg;
+ struct w1_netlink_cmd *cmd;
+
+ cmsg = kzalloc(sizeof(*msg) + sizeof(*cmd) + sizeof(*cmsg), GFP_KERNEL);
+ if (!cmsg)
+ return -ENOMEM;
+
+ msg = (struct w1_netlink_msg *)(cmsg + 1);
+ cmd = (struct w1_netlink_cmd *)(msg + 1);
+
+ memcpy(cmsg, rcmsg, sizeof(*cmsg));
+ cmsg->len = sizeof(*msg);
+
+ memcpy(msg, rmsg, sizeof(*msg));
+ msg->len = 0;
+ msg->status = (short)-error;
+
+ if (rcmd) {
+ memcpy(cmd, rcmd, sizeof(*cmd));
+ cmd->len = 0;
+ msg->len += sizeof(*cmd);
+ cmsg->len += sizeof(*cmd);
+ }
+
+ error = cn_netlink_send(cmsg, 0, GFP_KERNEL);
+ kfree(cmsg);
+
+ return error;
+}
+
static void w1_cn_callback(void *data)
{
struct cn_msg *msg = data;
@@ -144,6 +322,7 @@ static void w1_cn_callback(void *data)
dev = NULL;
sl = NULL;
+ cmd = NULL;
memcpy(&id, m->id.id, sizeof(id));
#if 0
@@ -155,15 +334,15 @@ static void w1_cn_callback(void *data)
break;
}
- if (!mlen)
- goto out_cont;
-
if (m->type == W1_MASTER_CMD) {
dev = w1_search_master_id(m->id.mst.id);
} else if (m->type == W1_SLAVE_CMD) {
sl = w1_search_slave(&id);
if (sl)
dev = sl->master;
+ } else {
+ err = w1_process_command_root(msg, m);
+ goto out_cont;
}
if (!dev) {
@@ -171,6 +350,10 @@ static void w1_cn_callback(void *data)
goto out_cont;
}
+ err = 0;
+ if (!mlen)
+ goto out_cont;
+
mutex_lock(&dev->mutex);
if (sl && w1_reset_select_slave(sl)) {
@@ -187,9 +370,12 @@ static void w1_cn_callback(void *data)
}
if (sl)
- w1_process_command_slave(sl, msg, m, cmd);
+ err = w1_process_command_slave(sl, msg, m, cmd);
else
- w1_process_command_master(dev, msg, m, cmd);
+ err = w1_process_command_master(dev, msg, m, cmd);
+
+ w1_netlink_send_error(msg, m, cmd, err);
+ err = 0;
cmd_data += cmd->len + sizeof(struct w1_netlink_cmd);
mlen -= cmd->len + sizeof(struct w1_netlink_cmd);
@@ -200,6 +386,8 @@ out_up:
atomic_dec(&sl->refcnt);
mutex_unlock(&dev->mutex);
out_cont:
+ if (!cmd || err)
+ w1_netlink_send_error(msg, m, cmd, err);
msg->len -= sizeof(struct w1_netlink_msg) + m->len;
m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len);
@@ -209,11 +397,6 @@ out_cont:
if (err == -ENODEV)
err = 0;
}
-#if 0
- if (err) {
- printk("%s: malformed message. Dropping.\n", __func__);
- }
-#endif
}
int w1_init_netlink(void)
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h
index 56122b9e9294..27e950f935b1 100644
--- a/drivers/w1/w1_netlink.h
+++ b/drivers/w1/w1_netlink.h
@@ -34,12 +34,13 @@ enum w1_netlink_message_types {
W1_MASTER_REMOVE,
W1_MASTER_CMD,
W1_SLAVE_CMD,
+ W1_LIST_MASTERS,
};
struct w1_netlink_msg
{
__u8 type;
- __u8 reserved;
+ __u8 status;
__u16 len;
union {
__u8 id[8];
@@ -51,10 +52,15 @@ struct w1_netlink_msg
__u8 data[0];
};
-#define W1_CMD_READ 0x0
-#define W1_CMD_WRITE 0x1
-#define W1_CMD_SEARCH 0x2
-#define W1_CMD_ALARM_SEARCH 0x3
+enum w1_commands {
+ W1_CMD_READ = 0,
+ W1_CMD_WRITE,
+ W1_CMD_SEARCH,
+ W1_CMD_ALARM_SEARCH,
+ W1_CMD_TOUCH,
+ W1_CMD_RESET,
+ W1_CMD_MAX,
+};
struct w1_netlink_cmd
{
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index ec68c741b564..3efa12f9ee50 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -770,6 +770,12 @@ config TXX9_WDT
# POWERPC Architecture
+config GEF_WDT
+ tristate "GE Fanuc Watchdog Timer"
+ depends on GEF_SBC610
+ ---help---
+ Watchdog timer found in a number of GE Fanuc single board computers.
+
config MPC5200_WDT
tristate "MPC5200 Watchdog Timer"
depends on PPC_MPC52xx
@@ -790,6 +796,14 @@ config MV64X60_WDT
tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
depends on MV64X60
+config PIKA_WDT
+ tristate "PIKA FPGA Watchdog"
+ depends on WARP
+ default y
+ help
+ This enables the watchdog in the PIKA FPGA. Currently used on
+ the Warp platform.
+
config BOOKE_WDT
bool "PowerPC Book-E Watchdog Timer"
depends on BOOKE || 4xx
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index c19b866f5ed1..806b3eb08536 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -111,9 +111,11 @@ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
# PARISC Architecture
# POWERPC Architecture
+obj-$(CONFIG_GEF_WDT) += gef_wdt.o
obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o
obj-$(CONFIG_8xxx_WDT) += mpc8xxx_wdt.o
obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
+obj-$(CONFIG_PIKA_WDT) += pika_wdt.o
obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
# PPC64 Architecture
diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c
new file mode 100644
index 000000000000..f0c2b7a1a175
--- /dev/null
+++ b/drivers/watchdog/gef_wdt.c
@@ -0,0 +1,330 @@
+/*
+ * GE Fanuc watchdog userspace interface
+ *
+ * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ *
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, 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 of the License, or (at your
+ * option) any later version.
+ *
+ * Based on: mv64x60_wdt.c (MV64X60 watchdog userspace interface)
+ * Author: James Chapman <jchapman@katalix.com>
+ */
+
+/* TODO:
+ * This driver does not provide support for the hardwares capability of sending
+ * an interrupt at a programmable threshold.
+ *
+ * This driver currently can only support 1 watchdog - there are 2 in the
+ * hardware that this driver supports. Thus one could be configured as a
+ * process-based watchdog (via /dev/watchdog), the second (using the interrupt
+ * capabilities) a kernel-based watchdog.
+ */
+
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <sysdev/fsl_soc.h>
+
+/*
+ * The watchdog configuration register contains a pair of 2-bit fields,
+ * 1. a reload field, bits 27-26, which triggers a reload of
+ * the countdown register, and
+ * 2. an enable field, bits 25-24, which toggles between
+ * enabling and disabling the watchdog timer.
+ * Bit 31 is a read-only field which indicates whether the
+ * watchdog timer is currently enabled.
+ *
+ * The low 24 bits contain the timer reload value.
+ */
+#define GEF_WDC_ENABLE_SHIFT 24
+#define GEF_WDC_SERVICE_SHIFT 26
+#define GEF_WDC_ENABLED_SHIFT 31
+
+#define GEF_WDC_ENABLED_TRUE 1
+#define GEF_WDC_ENABLED_FALSE 0
+
+/* Flags bits */
+#define GEF_WDOG_FLAG_OPENED 0
+
+static unsigned long wdt_flags;
+static int wdt_status;
+static void __iomem *gef_wdt_regs;
+static int gef_wdt_timeout;
+static int gef_wdt_count;
+static unsigned int bus_clk;
+static char expect_close;
+static DEFINE_SPINLOCK(gef_wdt_spinlock);
+
+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) ")");
+
+
+static int gef_wdt_toggle_wdc(int enabled_predicate, int field_shift)
+{
+ u32 data;
+ u32 enabled;
+ int ret = 0;
+
+ spin_lock(&gef_wdt_spinlock);
+ data = ioread32be(gef_wdt_regs);
+ enabled = (data >> GEF_WDC_ENABLED_SHIFT) & 1;
+
+ /* only toggle the requested field if enabled state matches predicate */
+ if ((enabled ^ enabled_predicate) == 0) {
+ /* We write a 1, then a 2 -- to the appropriate field */
+ data = (1 << field_shift) | gef_wdt_count;
+ iowrite32be(data, gef_wdt_regs);
+
+ data = (2 << field_shift) | gef_wdt_count;
+ iowrite32be(data, gef_wdt_regs);
+ ret = 1;
+ }
+ spin_unlock(&gef_wdt_spinlock);
+
+ return ret;
+}
+
+static void gef_wdt_service(void)
+{
+ gef_wdt_toggle_wdc(GEF_WDC_ENABLED_TRUE,
+ GEF_WDC_SERVICE_SHIFT);
+}
+
+static void gef_wdt_handler_enable(void)
+{
+ if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_FALSE,
+ GEF_WDC_ENABLE_SHIFT)) {
+ gef_wdt_service();
+ printk(KERN_NOTICE "gef_wdt: watchdog activated\n");
+ }
+}
+
+static void gef_wdt_handler_disable(void)
+{
+ if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_TRUE,
+ GEF_WDC_ENABLE_SHIFT))
+ printk(KERN_NOTICE "gef_wdt: watchdog deactivated\n");
+}
+
+static void gef_wdt_set_timeout(unsigned int timeout)
+{
+ /* maximum bus cycle count is 0xFFFFFFFF */
+ if (timeout > 0xFFFFFFFF / bus_clk)
+ timeout = 0xFFFFFFFF / bus_clk;
+
+ /* Register only holds upper 24 bits, bit shifted into lower 24 */
+ gef_wdt_count = (timeout * bus_clk) >> 8;
+ gef_wdt_timeout = timeout;
+}
+
+
+static ssize_t gef_wdt_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 = 42;
+ }
+ }
+ gef_wdt_service();
+ }
+
+ return len;
+}
+
+static long gef_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int timeout;
+ int options;
+ void __user *argp = (void __user *)arg;
+ static struct watchdog_info info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
+ WDIOF_KEEPALIVEPING,
+ .firmware_version = 0,
+ .identity = "GE Fanuc watchdog",
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user(argp, &info, sizeof(info)))
+ return -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ if (put_user(wdt_status, (int __user *)argp))
+ return -EFAULT;
+ wdt_status &= ~WDIOF_KEEPALIVEPING;
+ break;
+
+ case WDIOC_SETOPTIONS:
+ if (get_user(options, (int __user *)argp))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD)
+ gef_wdt_handler_disable();
+
+ if (options & WDIOS_ENABLECARD)
+ gef_wdt_handler_enable();
+ break;
+
+ case WDIOC_KEEPALIVE:
+ gef_wdt_service();
+ wdt_status |= WDIOF_KEEPALIVEPING;
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(timeout, (int __user *)argp))
+ return -EFAULT;
+ gef_wdt_set_timeout(timeout);
+ /* Fall through */
+
+ case WDIOC_GETTIMEOUT:
+ if (put_user(gef_wdt_timeout, (int __user *)argp))
+ return -EFAULT;
+ break;
+
+ default:
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+static int gef_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(GEF_WDOG_FLAG_OPENED, &wdt_flags))
+ return -EBUSY;
+
+ if (nowayout)
+ __module_get(THIS_MODULE);
+
+ gef_wdt_handler_enable();
+
+ return nonseekable_open(inode, file);
+}
+
+static int gef_wdt_release(struct inode *inode, struct file *file)
+{
+ if (expect_close == 42)
+ gef_wdt_handler_disable();
+ else {
+ printk(KERN_CRIT
+ "gef_wdt: unexpected close, not stopping timer!\n");
+ gef_wdt_service();
+ }
+ expect_close = 0;
+
+ clear_bit(GEF_WDOG_FLAG_OPENED, &wdt_flags);
+
+ return 0;
+}
+
+static const struct file_operations gef_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = gef_wdt_write,
+ .unlocked_ioctl = gef_wdt_ioctl,
+ .open = gef_wdt_open,
+ .release = gef_wdt_release,
+};
+
+static struct miscdevice gef_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &gef_wdt_fops,
+};
+
+
+static int __devinit gef_wdt_probe(struct of_device *dev,
+ const struct of_device_id *match)
+{
+ int timeout = 10;
+ u32 freq;
+
+ bus_clk = 133; /* in MHz */
+
+ freq = fsl_get_sys_freq();
+ if (freq > 0)
+ bus_clk = freq;
+
+ /* Map devices registers into memory */
+ gef_wdt_regs = of_iomap(dev->node, 0);
+ if (gef_wdt_regs == NULL)
+ return -ENOMEM;
+
+ gef_wdt_set_timeout(timeout);
+
+ gef_wdt_handler_disable(); /* in case timer was already running */
+
+ return misc_register(&gef_wdt_miscdev);
+}
+
+static int __devexit gef_wdt_remove(struct platform_device *dev)
+{
+ misc_deregister(&gef_wdt_miscdev);
+
+ gef_wdt_handler_disable();
+
+ iounmap(gef_wdt_regs);
+
+ return 0;
+}
+
+static const struct of_device_id gef_wdt_ids[] = {
+ {
+ .compatible = "gef,fpga-wdt",
+ },
+ {},
+};
+
+static struct of_platform_driver gef_wdt_driver = {
+ .owner = THIS_MODULE,
+ .name = "gef_wdt",
+ .match_table = gef_wdt_ids,
+ .probe = gef_wdt_probe,
+};
+
+static int __init gef_wdt_init(void)
+{
+ printk(KERN_INFO "GE Fanuc watchdog driver\n");
+ return of_register_platform_driver(&gef_wdt_driver);
+}
+
+static void __exit gef_wdt_exit(void)
+{
+ of_unregister_platform_driver(&gef_wdt_driver);
+}
+
+module_init(gef_wdt_init);
+module_exit(gef_wdt_exit);
+
+MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com>");
+MODULE_DESCRIPTION("GE Fanuc watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform: gef_wdt");
diff --git a/drivers/watchdog/pika_wdt.c b/drivers/watchdog/pika_wdt.c
new file mode 100644
index 000000000000..2d22e996e996
--- /dev/null
+++ b/drivers/watchdog/pika_wdt.c
@@ -0,0 +1,301 @@
+/*
+ * PIKA FPGA based Watchdog Timer
+ *
+ * Copyright (c) 2008 PIKA Technologies
+ * Sean MacLennan <smaclennan@pikatech.com>
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/bitops.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+
+#define DRV_NAME "PIKA-WDT"
+#define PFX DRV_NAME ": "
+
+/* Hardware timeout in seconds */
+#define WDT_HW_TIMEOUT 2
+
+/* Timer heartbeat (500ms) */
+#define WDT_TIMEOUT (HZ/2)
+
+/* User land timeout */
+#define WDT_HEARTBEAT 15
+static int heartbeat = WDT_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
+ "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
+
+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) ")");
+
+static struct {
+ void __iomem *fpga;
+ unsigned long next_heartbeat; /* the next_heartbeat for the timer */
+ unsigned long open;
+ char expect_close;
+ int bootstatus;
+ struct timer_list timer; /* The timer that pings the watchdog */
+} pikawdt_private;
+
+static struct watchdog_info ident = {
+ .identity = DRV_NAME,
+ .options = WDIOF_CARDRESET |
+ WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+};
+
+/*
+ * Reload the watchdog timer. (ie, pat the watchdog)
+ */
+static inline void pikawdt_reset(void)
+{
+ /* -- FPGA: Reset Control Register (32bit R/W) (Offset: 0x14) --
+ * Bit 7, WTCHDG_EN: When set to 1, the watchdog timer is enabled.
+ * Once enabled, it cannot be disabled. The watchdog can be
+ * kicked by performing any write access to the reset
+ * control register (this register).
+ * Bit 8-11, WTCHDG_TIMEOUT_SEC: Sets the watchdog timeout value in
+ * seconds. Valid ranges are 1 to 15 seconds. The value can
+ * be modified dynamically.
+ */
+ unsigned reset = in_be32(pikawdt_private.fpga + 0x14);
+ /* enable with max timeout - 15 seconds */
+ reset |= (1 << 7) + (WDT_HW_TIMEOUT << 8);
+ out_be32(pikawdt_private.fpga + 0x14, reset);
+}
+
+/*
+ * Timer tick
+ */
+static void pikawdt_ping(unsigned long data)
+{
+ if (time_before(jiffies, pikawdt_private.next_heartbeat) ||
+ (!nowayout && !pikawdt_private.open)) {
+ pikawdt_reset();
+ mod_timer(&pikawdt_private.timer, jiffies + WDT_TIMEOUT);
+ } else
+ printk(KERN_CRIT PFX "I will reset your machine !\n");
+}
+
+
+static void pikawdt_keepalive(void)
+{
+ pikawdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+}
+
+static void pikawdt_start(void)
+{
+ pikawdt_keepalive();
+ mod_timer(&pikawdt_private.timer, jiffies + WDT_TIMEOUT);
+}
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int pikawdt_open(struct inode *inode, struct file *file)
+{
+ /* /dev/watchdog can only be opened once */
+ if (test_and_set_bit(0, &pikawdt_private.open))
+ return -EBUSY;
+
+ pikawdt_start();
+
+ return nonseekable_open(inode, file);
+}
+
+/*
+ * Close the watchdog device.
+ */
+static int pikawdt_release(struct inode *inode, struct file *file)
+{
+ /* stop internal ping */
+ if (!pikawdt_private.expect_close)
+ del_timer(&pikawdt_private.timer);
+
+ clear_bit(0, &pikawdt_private.open);
+ pikawdt_private.expect_close = 0;
+ return 0;
+}
+
+/*
+ * Pat the watchdog whenever device is written to.
+ */
+static ssize_t pikawdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ if (!len)
+ return 0;
+
+ /* Scan for magic character */
+ if (!nowayout) {
+ size_t i;
+
+ pikawdt_private.expect_close = 0;
+
+ for (i = 0; i < len; i++) {
+ char c;
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V') {
+ pikawdt_private.expect_close = 42;
+ break;
+ }
+ }
+ }
+
+ pikawdt_keepalive();
+
+ return len;
+}
+
+/*
+ * Handle commands from user-space.
+ */
+static long pikawdt_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int new_value;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ return put_user(0, p);
+
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(pikawdt_private.bootstatus, p);
+
+ case WDIOC_KEEPALIVE:
+ pikawdt_keepalive();
+ return 0;
+
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_value, p))
+ return -EFAULT;
+
+ heartbeat = new_value;
+ pikawdt_keepalive();
+
+ return put_user(new_value, p); /* return current value */
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(heartbeat, p);
+ }
+ return -ENOTTY;
+}
+
+
+static const struct file_operations pikawdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .open = pikawdt_open,
+ .release = pikawdt_release,
+ .write = pikawdt_write,
+ .unlocked_ioctl = pikawdt_ioctl,
+};
+
+static struct miscdevice pikawdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &pikawdt_fops,
+};
+
+static int __init pikawdt_init(void)
+{
+ struct device_node *np;
+ void __iomem *fpga;
+ static u32 post1;
+ int ret;
+
+ np = of_find_compatible_node(NULL, NULL, "pika,fpga");
+ if (np == NULL) {
+ printk(KERN_ERR PFX "Unable to find fpga.\n");
+ return -ENOENT;
+ }
+
+ pikawdt_private.fpga = of_iomap(np, 0);
+ of_node_put(np);
+ if (pikawdt_private.fpga == NULL) {
+ printk(KERN_ERR PFX "Unable to map fpga.\n");
+ return -ENOMEM;
+ }
+
+ ident.firmware_version = in_be32(pikawdt_private.fpga + 0x1c) & 0xffff;
+
+ /* POST information is in the sd area. */
+ np = of_find_compatible_node(NULL, NULL, "pika,fpga-sd");
+ if (np == NULL) {
+ printk(KERN_ERR PFX "Unable to find fpga-sd.\n");
+ ret = -ENOENT;
+ goto out;
+ }
+
+ fpga = of_iomap(np, 0);
+ of_node_put(np);
+ if (fpga == NULL) {
+ printk(KERN_ERR PFX "Unable to map fpga-sd.\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* -- FPGA: POST Test Results Register 1 (32bit R/W) (Offset: 0x4040) --
+ * Bit 31, WDOG: Set to 1 when the last reset was caused by a watchdog
+ * timeout.
+ */
+ post1 = in_be32(fpga + 0x40);
+ if (post1 & 0x80000000)
+ pikawdt_private.bootstatus = WDIOF_CARDRESET;
+
+ iounmap(fpga);
+
+ setup_timer(&pikawdt_private.timer, pikawdt_ping, 0);
+
+ ret = misc_register(&pikawdt_miscdev);
+ if (ret) {
+ printk(KERN_ERR PFX "Unable to register miscdev.\n");
+ goto out;
+ }
+
+ printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+ heartbeat, nowayout);
+ return 0;
+
+out:
+ iounmap(pikawdt_private.fpga);
+ return ret;
+}
+
+static void __exit pikawdt_exit(void)
+{
+ misc_deregister(&pikawdt_miscdev);
+
+ iounmap(pikawdt_private.fpga);
+}
+
+module_init(pikawdt_init);
+module_exit(pikawdt_exit);
+
+MODULE_AUTHOR("Sean MacLennan <smaclennan@pikatech.com>");
+MODULE_DESCRIPTION("PIKA FPGA based Watchdog Timer");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
diff --git a/drivers/watchdog/wm8350_wdt.c b/drivers/watchdog/wm8350_wdt.c
index 2bc0d4d4b415..a2d2e8eb2282 100644
--- a/drivers/watchdog/wm8350_wdt.c
+++ b/drivers/watchdog/wm8350_wdt.c
@@ -279,7 +279,7 @@ static struct miscdevice wm8350_wdt_miscdev = {
.fops = &wm8350_wdt_fops,
};
-static int wm8350_wdt_probe(struct platform_device *pdev)
+static int __devinit wm8350_wdt_probe(struct platform_device *pdev)
{
struct wm8350 *wm8350 = platform_get_drvdata(pdev);
@@ -296,7 +296,7 @@ static int wm8350_wdt_probe(struct platform_device *pdev)
return misc_register(&wm8350_wdt_miscdev);
}
-static int __exit wm8350_wdt_remove(struct platform_device *pdev)
+static int __devexit wm8350_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&wm8350_wdt_miscdev);
@@ -305,7 +305,7 @@ static int __exit wm8350_wdt_remove(struct platform_device *pdev)
static struct platform_driver wm8350_wdt_driver = {
.probe = wm8350_wdt_probe,
- .remove = wm8350_wdt_remove,
+ .remove = __devexit_p(wm8350_wdt_remove),
.driver = {
.name = "wm8350-wdt",
},
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 4b75a16de009..526187c8a12d 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -17,3 +17,27 @@ config XEN_SCRUB_PAGES
is not accidentally visible to other domains. Is it more
secure, but slightly less efficient.
If in doubt, say yes.
+
+config XENFS
+ tristate "Xen filesystem"
+ depends on XEN
+ default y
+ help
+ The xen filesystem provides a way for domains to share
+ information with each other and with the hypervisor.
+ For example, by reading and writing the "xenbus" file, guests
+ may pass arbitrary information to the initial domain.
+ If in doubt, say yes.
+
+config XEN_COMPAT_XENFS
+ bool "Create compatibility mount point /proc/xen"
+ depends on XENFS
+ default y
+ help
+ The old xenstore userspace tools expect to find "xenbus"
+ under /proc/xen, but "xenbus" is now found at the root of the
+ xenfs filesystem. Selecting this causes the kernel to create
+ the compatibilty mount point /proc/xen if it is running on
+ a xen platform.
+ If in doubt, say yes.
+
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index d2a8fdf0e191..ff8accc9e103 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -1,5 +1,7 @@
obj-y += grant-table.o features.o events.o manage.o
obj-y += xenbus/
+
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
obj-$(CONFIG_XEN_BALLOON) += balloon.o
+obj-$(CONFIG_XENFS) += xenfs/ \ No newline at end of file
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
index 9678b3e98c63..92a1ef80a288 100644
--- a/drivers/xen/xenbus/xenbus_client.c
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -136,7 +136,6 @@ EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt);
/**
* xenbus_switch_state
* @dev: xenbus device
- * @xbt: transaction handle
* @state: new state
*
* Advertise in the store a change of the given driver to the given new_state.
@@ -267,7 +266,7 @@ EXPORT_SYMBOL_GPL(xenbus_dev_error);
* @fmt: error message format
*
* Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by
- * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly
+ * xenbus_switch_state(dev, XenbusStateClosing) to schedule an orderly
* closedown of this driver and its peer.
*/
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index b2a03184a246..773d1cf23283 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -40,6 +40,7 @@
#include <linux/ctype.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
+#include <linux/proc_fs.h>
#include <linux/notifier.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
@@ -55,7 +56,10 @@
#include "xenbus_comms.h"
#include "xenbus_probe.h"
+
int xen_store_evtchn;
+EXPORT_SYMBOL(xen_store_evtchn);
+
struct xenstore_domain_interface *xen_store_interface;
static unsigned long xen_store_mfn;
@@ -166,6 +170,9 @@ static int read_backend_details(struct xenbus_device *xendev)
return read_otherend_details(xendev, "backend-id", "backend");
}
+static struct device_attribute xenbus_dev_attrs[] = {
+ __ATTR_NULL
+};
/* Bus type for frontend drivers. */
static struct xen_bus_type xenbus_frontend = {
@@ -174,12 +181,13 @@ static struct xen_bus_type xenbus_frontend = {
.get_bus_id = frontend_bus_id,
.probe = xenbus_probe_frontend,
.bus = {
- .name = "xen",
- .match = xenbus_match,
- .uevent = xenbus_uevent,
- .probe = xenbus_dev_probe,
- .remove = xenbus_dev_remove,
- .shutdown = xenbus_dev_shutdown,
+ .name = "xen",
+ .match = xenbus_match,
+ .uevent = xenbus_uevent,
+ .probe = xenbus_dev_probe,
+ .remove = xenbus_dev_remove,
+ .shutdown = xenbus_dev_shutdown,
+ .dev_attrs = xenbus_dev_attrs,
},
};
@@ -852,6 +860,14 @@ static int __init xenbus_probe_init(void)
if (!xen_initial_domain())
xenbus_probe(NULL);
+#ifdef CONFIG_XEN_COMPAT_XENFS
+ /*
+ * Create xenfs mountpoint in /proc for compatibility with
+ * utilities that expect to find "xenbus" under "/proc/xen".
+ */
+ proc_mkdir("xen", NULL);
+#endif
+
return 0;
out_unreg_back:
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
index 7f2f91c0e11d..e325eab4724d 100644
--- a/drivers/xen/xenbus/xenbus_xs.c
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -184,6 +184,7 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
return ret;
}
+EXPORT_SYMBOL(xenbus_dev_request_and_reply);
/* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */
static void *xs_talkv(struct xenbus_transaction t,
diff --git a/drivers/xen/xenfs/Makefile b/drivers/xen/xenfs/Makefile
new file mode 100644
index 000000000000..25275c3bbdff
--- /dev/null
+++ b/drivers/xen/xenfs/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_XENFS) += xenfs.o
+
+xenfs-objs = super.o xenbus.o \ No newline at end of file
diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c
new file mode 100644
index 000000000000..515741a8e6b8
--- /dev/null
+++ b/drivers/xen/xenfs/super.c
@@ -0,0 +1,64 @@
+/*
+ * xenfs.c - a filesystem for passing info between the a domain and
+ * the hypervisor.
+ *
+ * 2008-10-07 Alex Zeffertt Replaced /proc/xen/xenbus with xenfs filesystem
+ * and /proc/xen compatibility mount point.
+ * Turned xenfs into a loadable module.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/magic.h>
+
+#include "xenfs.h"
+
+#include <asm/xen/hypervisor.h>
+
+MODULE_DESCRIPTION("Xen filesystem");
+MODULE_LICENSE("GPL");
+
+static int xenfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+ static struct tree_descr xenfs_files[] = {
+ [2] = {"xenbus", &xenbus_file_ops, S_IRUSR|S_IWUSR},
+ {""},
+ };
+
+ return simple_fill_super(sb, XENFS_SUPER_MAGIC, xenfs_files);
+}
+
+static int xenfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data, struct vfsmount *mnt)
+{
+ return get_sb_single(fs_type, flags, data, xenfs_fill_super, mnt);
+}
+
+static struct file_system_type xenfs_type = {
+ .owner = THIS_MODULE,
+ .name = "xenfs",
+ .get_sb = xenfs_get_sb,
+ .kill_sb = kill_litter_super,
+};
+
+static int __init xenfs_init(void)
+{
+ if (xen_pv_domain())
+ return register_filesystem(&xenfs_type);
+
+ printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n");
+ return 0;
+}
+
+static void __exit xenfs_exit(void)
+{
+ if (xen_pv_domain())
+ unregister_filesystem(&xenfs_type);
+}
+
+module_init(xenfs_init);
+module_exit(xenfs_exit);
+
diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c
new file mode 100644
index 000000000000..875a4c59c594
--- /dev/null
+++ b/drivers/xen/xenfs/xenbus.c
@@ -0,0 +1,593 @@
+/*
+ * Driver giving user-space access to the kernel's xenbus connection
+ * to xenstore.
+ *
+ * Copyright (c) 2005, Christian Limpach
+ * Copyright (c) 2005, Rusty Russell, IBM Corporation
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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.
+ *
+ * Changes:
+ * 2008-10-07 Alex Zeffertt Replaced /proc/xen/xenbus with xenfs filesystem
+ * and /proc/xen compatibility mount point.
+ * Turned xenfs into a loadable module.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/uio.h>
+#include <linux/notifier.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/uaccess.h>
+#include <linux/init.h>
+#include <linux/namei.h>
+#include <linux/string.h>
+
+#include "xenfs.h"
+#include "../xenbus/xenbus_comms.h"
+
+#include <xen/xenbus.h>
+#include <asm/xen/hypervisor.h>
+
+/*
+ * An element of a list of outstanding transactions, for which we're
+ * still waiting a reply.
+ */
+struct xenbus_transaction_holder {
+ struct list_head list;
+ struct xenbus_transaction handle;
+};
+
+/*
+ * A buffer of data on the queue.
+ */
+struct read_buffer {
+ struct list_head list;
+ unsigned int cons;
+ unsigned int len;
+ char msg[];
+};
+
+struct xenbus_file_priv {
+ /*
+ * msgbuffer_mutex is held while partial requests are built up
+ * and complete requests are acted on. It therefore protects
+ * the "transactions" and "watches" lists, and the partial
+ * request length and buffer.
+ *
+ * reply_mutex protects the reply being built up to return to
+ * usermode. It nests inside msgbuffer_mutex but may be held
+ * alone during a watch callback.
+ */
+ struct mutex msgbuffer_mutex;
+
+ /* In-progress transactions */
+ struct list_head transactions;
+
+ /* Active watches. */
+ struct list_head watches;
+
+ /* Partial request. */
+ unsigned int len;
+ union {
+ struct xsd_sockmsg msg;
+ char buffer[PAGE_SIZE];
+ } u;
+
+ /* Response queue. */
+ struct mutex reply_mutex;
+ struct list_head read_buffers;
+ wait_queue_head_t read_waitq;
+
+};
+
+/* Read out any raw xenbus messages queued up. */
+static ssize_t xenbus_file_read(struct file *filp,
+ char __user *ubuf,
+ size_t len, loff_t *ppos)
+{
+ struct xenbus_file_priv *u = filp->private_data;
+ struct read_buffer *rb;
+ unsigned i;
+ int ret;
+
+ mutex_lock(&u->reply_mutex);
+ while (list_empty(&u->read_buffers)) {
+ mutex_unlock(&u->reply_mutex);
+ ret = wait_event_interruptible(u->read_waitq,
+ !list_empty(&u->read_buffers));
+ if (ret)
+ return ret;
+ mutex_lock(&u->reply_mutex);
+ }
+
+ rb = list_entry(u->read_buffers.next, struct read_buffer, list);
+ i = 0;
+ while (i < len) {
+ unsigned sz = min((unsigned)len - i, rb->len - rb->cons);
+
+ ret = copy_to_user(ubuf + i, &rb->msg[rb->cons], sz);
+
+ i += sz - ret;
+ rb->cons += sz - ret;
+
+ if (ret != sz) {
+ if (i == 0)
+ i = -EFAULT;
+ goto out;
+ }
+
+ /* Clear out buffer if it has been consumed */
+ if (rb->cons == rb->len) {
+ list_del(&rb->list);
+ kfree(rb);
+ if (list_empty(&u->read_buffers))
+ break;
+ rb = list_entry(u->read_buffers.next,
+ struct read_buffer, list);
+ }
+ }
+
+out:
+ mutex_unlock(&u->reply_mutex);
+ return i;
+}
+
+/*
+ * Add a buffer to the queue. Caller must hold the appropriate lock
+ * if the queue is not local. (Commonly the caller will build up
+ * multiple queued buffers on a temporary local list, and then add it
+ * to the appropriate list under lock once all the buffers have een
+ * successfully allocated.)
+ */
+static int queue_reply(struct list_head *queue, const void *data, size_t len)
+{
+ struct read_buffer *rb;
+
+ if (len == 0)
+ return 0;
+
+ rb = kmalloc(sizeof(*rb) + len, GFP_KERNEL);
+ if (rb == NULL)
+ return -ENOMEM;
+
+ rb->cons = 0;
+ rb->len = len;
+
+ memcpy(rb->msg, data, len);
+
+ list_add_tail(&rb->list, queue);
+ return 0;
+}
+
+/*
+ * Free all the read_buffer s on a list.
+ * Caller must have sole reference to list.
+ */
+static void queue_cleanup(struct list_head *list)
+{
+ struct read_buffer *rb;
+
+ while (!list_empty(list)) {
+ rb = list_entry(list->next, struct read_buffer, list);
+ list_del(list->next);
+ kfree(rb);
+ }
+}
+
+struct watch_adapter {
+ struct list_head list;
+ struct xenbus_watch watch;
+ struct xenbus_file_priv *dev_data;
+ char *token;
+};
+
+static void free_watch_adapter(struct watch_adapter *watch)
+{
+ kfree(watch->watch.node);
+ kfree(watch->token);
+ kfree(watch);
+}
+
+static struct watch_adapter *alloc_watch_adapter(const char *path,
+ const char *token)
+{
+ struct watch_adapter *watch;
+
+ watch = kzalloc(sizeof(*watch), GFP_KERNEL);
+ if (watch == NULL)
+ goto out_fail;
+
+ watch->watch.node = kstrdup(path, GFP_KERNEL);
+ if (watch->watch.node == NULL)
+ goto out_free;
+
+ watch->token = kstrdup(token, GFP_KERNEL);
+ if (watch->token == NULL)
+ goto out_free;
+
+ return watch;
+
+out_free:
+ free_watch_adapter(watch);
+
+out_fail:
+ return NULL;
+}
+
+static void watch_fired(struct xenbus_watch *watch,
+ const char **vec,
+ unsigned int len)
+{
+ struct watch_adapter *adap;
+ struct xsd_sockmsg hdr;
+ const char *path, *token;
+ int path_len, tok_len, body_len, data_len = 0;
+ int ret;
+ LIST_HEAD(staging_q);
+
+ adap = container_of(watch, struct watch_adapter, watch);
+
+ path = vec[XS_WATCH_PATH];
+ token = adap->token;
+
+ path_len = strlen(path) + 1;
+ tok_len = strlen(token) + 1;
+ if (len > 2)
+ data_len = vec[len] - vec[2] + 1;
+ body_len = path_len + tok_len + data_len;
+
+ hdr.type = XS_WATCH_EVENT;
+ hdr.len = body_len;
+
+ mutex_lock(&adap->dev_data->reply_mutex);
+
+ ret = queue_reply(&staging_q, &hdr, sizeof(hdr));
+ if (!ret)
+ ret = queue_reply(&staging_q, path, path_len);
+ if (!ret)
+ ret = queue_reply(&staging_q, token, tok_len);
+ if (!ret && len > 2)
+ ret = queue_reply(&staging_q, vec[2], data_len);
+
+ if (!ret) {
+ /* success: pass reply list onto watcher */
+ list_splice_tail(&staging_q, &adap->dev_data->read_buffers);
+ wake_up(&adap->dev_data->read_waitq);
+ } else
+ queue_cleanup(&staging_q);
+
+ mutex_unlock(&adap->dev_data->reply_mutex);
+}
+
+static int xenbus_write_transaction(unsigned msg_type,
+ struct xenbus_file_priv *u)
+{
+ int rc, ret;
+ void *reply;
+ struct xenbus_transaction_holder *trans = NULL;
+ LIST_HEAD(staging_q);
+
+ if (msg_type == XS_TRANSACTION_START) {
+ trans = kmalloc(sizeof(*trans), GFP_KERNEL);
+ if (!trans) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ }
+
+ reply = xenbus_dev_request_and_reply(&u->u.msg);
+ if (IS_ERR(reply)) {
+ kfree(trans);
+ rc = PTR_ERR(reply);
+ goto out;
+ }
+
+ if (msg_type == XS_TRANSACTION_START) {
+ trans->handle.id = simple_strtoul(reply, NULL, 0);
+
+ list_add(&trans->list, &u->transactions);
+ } else if (msg_type == XS_TRANSACTION_END) {
+ list_for_each_entry(trans, &u->transactions, list)
+ if (trans->handle.id == u->u.msg.tx_id)
+ break;
+ BUG_ON(&trans->list == &u->transactions);
+ list_del(&trans->list);
+
+ kfree(trans);
+ }
+
+ mutex_lock(&u->reply_mutex);
+ ret = queue_reply(&staging_q, &u->u.msg, sizeof(u->u.msg));
+ if (!ret)
+ ret = queue_reply(&staging_q, reply, u->u.msg.len);
+ if (!ret) {
+ list_splice_tail(&staging_q, &u->read_buffers);
+ wake_up(&u->read_waitq);
+ } else {
+ queue_cleanup(&staging_q);
+ rc = ret;
+ }
+ mutex_unlock(&u->reply_mutex);
+
+ kfree(reply);
+
+out:
+ return rc;
+}
+
+static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u)
+{
+ struct watch_adapter *watch, *tmp_watch;
+ char *path, *token;
+ int err, rc;
+ LIST_HEAD(staging_q);
+
+ path = u->u.buffer + sizeof(u->u.msg);
+ token = memchr(path, 0, u->u.msg.len);
+ if (token == NULL) {
+ rc = -EILSEQ;
+ goto out;
+ }
+ token++;
+
+ if (msg_type == XS_WATCH) {
+ watch = alloc_watch_adapter(path, token);
+ if (watch == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ watch->watch.callback = watch_fired;
+ watch->dev_data = u;
+
+ err = register_xenbus_watch(&watch->watch);
+ if (err) {
+ free_watch_adapter(watch);
+ rc = err;
+ goto out;
+ }
+ list_add(&watch->list, &u->watches);
+ } else {
+ list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
+ if (!strcmp(watch->token, token) &&
+ !strcmp(watch->watch.node, path)) {
+ unregister_xenbus_watch(&watch->watch);
+ list_del(&watch->list);
+ free_watch_adapter(watch);
+ break;
+ }
+ }
+ }
+
+ /* Success. Synthesize a reply to say all is OK. */
+ {
+ struct {
+ struct xsd_sockmsg hdr;
+ char body[3];
+ } __packed reply = {
+ {
+ .type = msg_type,
+ .len = sizeof(reply.body)
+ },
+ "OK"
+ };
+
+ mutex_lock(&u->reply_mutex);
+ rc = queue_reply(&u->read_buffers, &reply, sizeof(reply));
+ mutex_unlock(&u->reply_mutex);
+ }
+
+out:
+ return rc;
+}
+
+static ssize_t xenbus_file_write(struct file *filp,
+ const char __user *ubuf,
+ size_t len, loff_t *ppos)
+{
+ struct xenbus_file_priv *u = filp->private_data;
+ uint32_t msg_type;
+ int rc = len;
+ int ret;
+ LIST_HEAD(staging_q);
+
+ /*
+ * We're expecting usermode to be writing properly formed
+ * xenbus messages. If they write an incomplete message we
+ * buffer it up. Once it is complete, we act on it.
+ */
+
+ /*
+ * Make sure concurrent writers can't stomp all over each
+ * other's messages and make a mess of our partial message
+ * buffer. We don't make any attemppt to stop multiple
+ * writers from making a mess of each other's incomplete
+ * messages; we're just trying to guarantee our own internal
+ * consistency and make sure that single writes are handled
+ * atomically.
+ */
+ mutex_lock(&u->msgbuffer_mutex);
+
+ /* Get this out of the way early to avoid confusion */
+ if (len == 0)
+ goto out;
+
+ /* Can't write a xenbus message larger we can buffer */
+ if ((len + u->len) > sizeof(u->u.buffer)) {
+ /* On error, dump existing buffer */
+ u->len = 0;
+ rc = -EINVAL;
+ goto out;
+ }
+
+ ret = copy_from_user(u->u.buffer + u->len, ubuf, len);
+
+ if (ret == len) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ /* Deal with a partial copy. */
+ len -= ret;
+ rc = len;
+
+ u->len += len;
+
+ /* Return if we haven't got a full message yet */
+ if (u->len < sizeof(u->u.msg))
+ goto out; /* not even the header yet */
+
+ /* If we're expecting a message that's larger than we can
+ possibly send, dump what we have and return an error. */
+ if ((sizeof(u->u.msg) + u->u.msg.len) > sizeof(u->u.buffer)) {
+ rc = -E2BIG;
+ u->len = 0;
+ goto out;
+ }
+
+ if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
+ goto out; /* incomplete data portion */
+
+ /*
+ * OK, now we have a complete message. Do something with it.
+ */
+
+ msg_type = u->u.msg.type;
+
+ switch (msg_type) {
+ case XS_TRANSACTION_START:
+ case XS_TRANSACTION_END:
+ case XS_DIRECTORY:
+ case XS_READ:
+ case XS_GET_PERMS:
+ case XS_RELEASE:
+ case XS_GET_DOMAIN_PATH:
+ case XS_WRITE:
+ case XS_MKDIR:
+ case XS_RM:
+ case XS_SET_PERMS:
+ /* Send out a transaction */
+ ret = xenbus_write_transaction(msg_type, u);
+ break;
+
+ case XS_WATCH:
+ case XS_UNWATCH:
+ /* (Un)Ask for some path to be watched for changes */
+ ret = xenbus_write_watch(msg_type, u);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret != 0)
+ rc = ret;
+
+ /* Buffered message consumed */
+ u->len = 0;
+
+ out:
+ mutex_unlock(&u->msgbuffer_mutex);
+ return rc;
+}
+
+static int xenbus_file_open(struct inode *inode, struct file *filp)
+{
+ struct xenbus_file_priv *u;
+
+ if (xen_store_evtchn == 0)
+ return -ENOENT;
+
+ nonseekable_open(inode, filp);
+
+ u = kzalloc(sizeof(*u), GFP_KERNEL);
+ if (u == NULL)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&u->transactions);
+ INIT_LIST_HEAD(&u->watches);
+ INIT_LIST_HEAD(&u->read_buffers);
+ init_waitqueue_head(&u->read_waitq);
+
+ mutex_init(&u->reply_mutex);
+ mutex_init(&u->msgbuffer_mutex);
+
+ filp->private_data = u;
+
+ return 0;
+}
+
+static int xenbus_file_release(struct inode *inode, struct file *filp)
+{
+ struct xenbus_file_priv *u = filp->private_data;
+ struct xenbus_transaction_holder *trans, *tmp;
+ struct watch_adapter *watch, *tmp_watch;
+
+ /*
+ * No need for locking here because there are no other users,
+ * by definition.
+ */
+
+ list_for_each_entry_safe(trans, tmp, &u->transactions, list) {
+ xenbus_transaction_end(trans->handle, 1);
+ list_del(&trans->list);
+ kfree(trans);
+ }
+
+ list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) {
+ unregister_xenbus_watch(&watch->watch);
+ list_del(&watch->list);
+ free_watch_adapter(watch);
+ }
+
+ kfree(u);
+
+ return 0;
+}
+
+static unsigned int xenbus_file_poll(struct file *file, poll_table *wait)
+{
+ struct xenbus_file_priv *u = file->private_data;
+
+ poll_wait(file, &u->read_waitq, wait);
+ if (!list_empty(&u->read_buffers))
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+const struct file_operations xenbus_file_ops = {
+ .read = xenbus_file_read,
+ .write = xenbus_file_write,
+ .open = xenbus_file_open,
+ .release = xenbus_file_release,
+ .poll = xenbus_file_poll,
+};
diff --git a/drivers/xen/xenfs/xenfs.h b/drivers/xen/xenfs/xenfs.h
new file mode 100644
index 000000000000..51f08b2d0bf1
--- /dev/null
+++ b/drivers/xen/xenfs/xenfs.h
@@ -0,0 +1,6 @@
+#ifndef _XENFS_XENBUS_H
+#define _XENFS_XENBUS_H
+
+extern const struct file_operations xenbus_file_ops;
+
+#endif /* _XENFS_XENBUS_H */
diff --git a/drivers/zorro/.gitignore b/drivers/zorro/.gitignore
new file mode 100644
index 000000000000..34f980bd8ff6
--- /dev/null
+++ b/drivers/zorro/.gitignore
@@ -0,0 +1,2 @@
+devlist.h
+gen-devlist
diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c
index 5290552d2ef7..1d2a772ea14c 100644
--- a/drivers/zorro/zorro-sysfs.c
+++ b/drivers/zorro/zorro-sysfs.c
@@ -77,17 +77,21 @@ static struct bin_attribute zorro_config_attr = {
.read = zorro_read_config,
};
-void zorro_create_sysfs_dev_files(struct zorro_dev *z)
+int zorro_create_sysfs_dev_files(struct zorro_dev *z)
{
struct device *dev = &z->dev;
+ int error;
/* current configuration's attributes */
- device_create_file(dev, &dev_attr_id);
- device_create_file(dev, &dev_attr_type);
- device_create_file(dev, &dev_attr_serial);
- device_create_file(dev, &dev_attr_slotaddr);
- device_create_file(dev, &dev_attr_slotsize);
- device_create_file(dev, &dev_attr_resource);
- sysfs_create_bin_file(&dev->kobj, &zorro_config_attr);
+ if ((error = device_create_file(dev, &dev_attr_id)) ||
+ (error = device_create_file(dev, &dev_attr_type)) ||
+ (error = device_create_file(dev, &dev_attr_serial)) ||
+ (error = device_create_file(dev, &dev_attr_slotaddr)) ||
+ (error = device_create_file(dev, &dev_attr_slotsize)) ||
+ (error = device_create_file(dev, &dev_attr_resource)) ||
+ (error = sysfs_create_bin_file(&dev->kobj, &zorro_config_attr)))
+ return error;
+
+ return 0;
}
diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c
index dff16d9767d8..a1585d6f6486 100644
--- a/drivers/zorro/zorro.c
+++ b/drivers/zorro/zorro.c
@@ -130,6 +130,7 @@ static int __init zorro_init(void)
{
struct zorro_dev *z;
unsigned int i;
+ int error;
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
return 0;
@@ -140,7 +141,11 @@ static int __init zorro_init(void)
/* Initialize the Zorro bus */
INIT_LIST_HEAD(&zorro_bus.devices);
strcpy(zorro_bus.dev.bus_id, "zorro");
- device_register(&zorro_bus.dev);
+ error = device_register(&zorro_bus.dev);
+ if (error) {
+ pr_err("Zorro: Error registering zorro_bus\n");
+ return error;
+ }
/* Request the resources */
zorro_bus.num_resources = AMIGAHW_PRESENT(ZORRO3) ? 4 : 2;
@@ -160,15 +165,19 @@ static int __init zorro_init(void)
zorro_name_device(z);
z->resource.name = z->name;
if (request_resource(zorro_find_parent_resource(z), &z->resource))
- printk(KERN_ERR "Zorro: Address space collision on device %s "
- "[%lx:%lx]\n",
- z->name, (unsigned long)zorro_resource_start(z),
- (unsigned long)zorro_resource_end(z));
+ pr_err("Zorro: Address space collision on device %s %pR\n",
+ z->name, &z->resource);
sprintf(z->dev.bus_id, "%02x", i);
z->dev.parent = &zorro_bus.dev;
z->dev.bus = &zorro_bus_type;
- device_register(&z->dev);
- zorro_create_sysfs_dev_files(z);
+ error = device_register(&z->dev);
+ if (error) {
+ pr_err("Zorro: Error registering device %s\n", z->name);
+ continue;
+ }
+ error = zorro_create_sysfs_dev_files(z);
+ if (error)
+ dev_err(&z->dev, "Error creating sysfs files\n");
}
/* Mark all available Zorro II memory */
diff --git a/drivers/zorro/zorro.h b/drivers/zorro/zorro.h
index 5c91adac4df1..b682d5ccd63f 100644
--- a/drivers/zorro/zorro.h
+++ b/drivers/zorro/zorro.h
@@ -1,4 +1,4 @@
extern void zorro_name_device(struct zorro_dev *z);
-extern void zorro_create_sysfs_dev_files(struct zorro_dev *z);
+extern int zorro_create_sysfs_dev_files(struct zorro_dev *z);